"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const THREE = require("three"); const chevrotain = require("../libs/chevrotain.cjs"); class VRMLLoader extends THREE.Loader { constructor(manager) { super(manager); } load(url, onLoad, onProgress, onError) { const scope = this; const path = scope.path === "" ? THREE.LoaderUtils.extractUrlBase(url) : scope.path; const loader = new THREE.FileLoader(scope.manager); loader.setPath(scope.path); loader.setRequestHeader(scope.requestHeader); loader.setWithCredentials(scope.withCredentials); loader.load( url, function(text) { try { onLoad(scope.parse(text, path)); } catch (e) { if (onError) { onError(e); } else { console.error(e); } scope.manager.itemError(url); } }, onProgress, onError ); } parse(data, path) { const nodeMap = {}; function generateVRMLTree(data2) { const tokenData = createTokens(); const lexer = new VRMLLexer(tokenData.tokens); const parser = new VRMLParser(tokenData.tokenVocabulary); const visitor = createVisitor(parser.getBaseCstVisitorConstructor()); const lexingResult = lexer.lex(data2); parser.input = lexingResult.tokens; const cstOutput = parser.vrml(); if (parser.errors.length > 0) { console.error(parser.errors); throw Error("THREE.VRMLLoader: Parsing errors detected."); } const ast = visitor.visit(cstOutput); return ast; } function createTokens() { const RouteIdentifier = chevrotain.createToken({ name: "RouteIdentifier", pattern: /[^\x30-\x39\0-\x20\x22\x27\x23\x2b\x2c\x2d\x2e\x5b\x5d\x5c\x7b\x7d][^\0-\x20\x22\x27\x23\x2b\x2c\x2d\x2e\x5b\x5d\x5c\x7b\x7d]*[\.][^\x30-\x39\0-\x20\x22\x27\x23\x2b\x2c\x2d\x2e\x5b\x5d\x5c\x7b\x7d][^\0-\x20\x22\x27\x23\x2b\x2c\x2d\x2e\x5b\x5d\x5c\x7b\x7d]*/ }); const Identifier = chevrotain.createToken({ name: "Identifier", pattern: /[^\x30-\x39\0-\x20\x22\x27\x23\x2b\x2c\x2d\x2e\x5b\x5d\x5c\x7b\x7d][^\0-\x20\x22\x27\x23\x2b\x2c\x2d\x2e\x5b\x5d\x5c\x7b\x7d]*/, longer_alt: RouteIdentifier }); const nodeTypes = [ "Anchor", "Billboard", "Collision", "Group", "Transform", // grouping nodes "Inline", "LOD", "Switch", // special groups "AudioClip", "DirectionalLight", "PointLight", "Script", "Shape", "Sound", "SpotLight", "WorldInfo", // common nodes "CylinderSensor", "PlaneSensor", "ProximitySensor", "SphereSensor", "TimeSensor", "TouchSensor", "VisibilitySensor", // sensors "Box", "Cone", "Cylinder", "ElevationGrid", "Extrusion", "IndexedFaceSet", "IndexedLineSet", "PointSet", "Sphere", // geometries "Color", "Coordinate", "Normal", "TextureCoordinate", // geometric properties "Appearance", "FontStyle", "ImageTexture", "Material", "MovieTexture", "PixelTexture", "TextureTransform", // appearance "ColorInterpolator", "CoordinateInterpolator", "NormalInterpolator", "OrientationInterpolator", "PositionInterpolator", "ScalarInterpolator", // interpolators "Background", "Fog", "NavigationInfo", "Viewpoint", // bindable nodes "Text" // Text must be placed at the end of the regex so there are no matches for TextureTransform and TextureCoordinate ]; const Version = chevrotain.createToken({ name: "Version", pattern: /#VRML.*/, longer_alt: Identifier }); const NodeName = chevrotain.createToken({ name: "NodeName", pattern: new RegExp(nodeTypes.join("|")), longer_alt: Identifier }); const DEF = chevrotain.createToken({ name: "DEF", pattern: /DEF/, longer_alt: Identifier }); const USE = chevrotain.createToken({ name: "USE", pattern: /USE/, longer_alt: Identifier }); const ROUTE = chevrotain.createToken({ name: "ROUTE", pattern: /ROUTE/, longer_alt: Identifier }); const TO = chevrotain.createToken({ name: "TO", pattern: /TO/, longer_alt: Identifier }); const StringLiteral = chevrotain.createToken({ name: "StringLiteral", pattern: /"(?:[^\\"\n\r]|\\[bfnrtv"\\/]|\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])*"/ }); const HexLiteral = chevrotain.createToken({ name: "HexLiteral", pattern: /0[xX][0-9a-fA-F]+/ }); const NumberLiteral = chevrotain.createToken({ name: "NumberLiteral", pattern: /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/ }); const TrueLiteral = chevrotain.createToken({ name: "TrueLiteral", pattern: /TRUE/ }); const FalseLiteral = chevrotain.createToken({ name: "FalseLiteral", pattern: /FALSE/ }); const NullLiteral = chevrotain.createToken({ name: "NullLiteral", pattern: /NULL/ }); const LSquare = chevrotain.createToken({ name: "LSquare", pattern: /\[/ }); const RSquare = chevrotain.createToken({ name: "RSquare", pattern: /]/ }); const LCurly = chevrotain.createToken({ name: "LCurly", pattern: /{/ }); const RCurly = chevrotain.createToken({ name: "RCurly", pattern: /}/ }); const Comment = chevrotain.createToken({ name: "Comment", pattern: /#.*/, group: chevrotain.Lexer.SKIPPED }); const WhiteSpace = chevrotain.createToken({ name: "WhiteSpace", pattern: /[ ,\s]/, group: chevrotain.Lexer.SKIPPED }); const tokens = [ WhiteSpace, // keywords appear before the Identifier NodeName, DEF, USE, ROUTE, TO, TrueLiteral, FalseLiteral, NullLiteral, // the Identifier must appear after the keywords because all keywords are valid identifiers Version, Identifier, RouteIdentifier, StringLiteral, HexLiteral, NumberLiteral, LSquare, RSquare, LCurly, RCurly, Comment ]; const tokenVocabulary = {}; for (let i = 0, l = tokens.length; i < l; i++) { const token = tokens[i]; tokenVocabulary[token.name] = token; } return { tokens, tokenVocabulary }; } function createVisitor(BaseVRMLVisitor) { function VRMLToASTVisitor() { BaseVRMLVisitor.call(this); this.validateVisitor(); } VRMLToASTVisitor.prototype = Object.assign(Object.create(BaseVRMLVisitor.prototype), { constructor: VRMLToASTVisitor, vrml: function(ctx) { const data2 = { version: this.visit(ctx.version), nodes: [], routes: [] }; for (let i = 0, l = ctx.node.length; i < l; i++) { const node = ctx.node[i]; data2.nodes.push(this.visit(node)); } if (ctx.route) { for (let i = 0, l = ctx.route.length; i < l; i++) { const route = ctx.route[i]; data2.routes.push(this.visit(route)); } } return data2; }, version: function(ctx) { return ctx.Version[0].image; }, node: function(ctx) { const data2 = { name: ctx.NodeName[0].image, fields: [] }; if (ctx.field) { for (let i = 0, l = ctx.field.length; i < l; i++) { const field = ctx.field[i]; data2.fields.push(this.visit(field)); } } if (ctx.def) { data2.DEF = this.visit(ctx.def[0]); } return data2; }, field: function(ctx) { const data2 = { name: ctx.Identifier[0].image, type: null, values: null }; let result; if (ctx.singleFieldValue) { result = this.visit(ctx.singleFieldValue[0]); } if (ctx.multiFieldValue) { result = this.visit(ctx.multiFieldValue[0]); } data2.type = result.type; data2.values = result.values; return data2; }, def: function(ctx) { return (ctx.Identifier || ctx.NodeName)[0].image; }, use: function(ctx) { return { USE: (ctx.Identifier || ctx.NodeName)[0].image }; }, singleFieldValue: function(ctx) { return processField(this, ctx); }, multiFieldValue: function(ctx) { return processField(this, ctx); }, route: function(ctx) { const data2 = { FROM: ctx.RouteIdentifier[0].image, TO: ctx.RouteIdentifier[1].image }; return data2; } }); function processField(scope, ctx) { const field = { type: null, values: [] }; if (ctx.node) { field.type = "node"; for (let i = 0, l = ctx.node.length; i < l; i++) { const node = ctx.node[i]; field.values.push(scope.visit(node)); } } if (ctx.use) { field.type = "use"; for (let i = 0, l = ctx.use.length; i < l; i++) { const use = ctx.use[i]; field.values.push(scope.visit(use)); } } if (ctx.StringLiteral) { field.type = "string"; for (let i = 0, l = ctx.StringLiteral.length; i < l; i++) { const stringLiteral = ctx.StringLiteral[i]; field.values.push(stringLiteral.image.replace(/'|"/g, "")); } } if (ctx.NumberLiteral) { field.type = "number"; for (let i = 0, l = ctx.NumberLiteral.length; i < l; i++) { const numberLiteral = ctx.NumberLiteral[i]; field.values.push(parseFloat(numberLiteral.image)); } } if (ctx.HexLiteral) { field.type = "hex"; for (let i = 0, l = ctx.HexLiteral.length; i < l; i++) { const hexLiteral = ctx.HexLiteral[i]; field.values.push(hexLiteral.image); } } if (ctx.TrueLiteral) { field.type = "boolean"; for (let i = 0, l = ctx.TrueLiteral.length; i < l; i++) { const trueLiteral = ctx.TrueLiteral[i]; if (trueLiteral.image === "TRUE") field.values.push(true); } } if (ctx.FalseLiteral) { field.type = "boolean"; for (let i = 0, l = ctx.FalseLiteral.length; i < l; i++) { const falseLiteral = ctx.FalseLiteral[i]; if (falseLiteral.image === "FALSE") field.values.push(false); } } if (ctx.NullLiteral) { field.type = "null"; ctx.NullLiteral.forEach(function() { field.values.push(null); }); } return field; } return new VRMLToASTVisitor(); } function parseTree(tree2) { const nodes = tree2.nodes; const scene2 = new THREE.Scene(); for (let i = 0, l = nodes.length; i < l; i++) { const node = nodes[i]; buildNodeMap(node); } for (let i = 0, l = nodes.length; i < l; i++) { const node = nodes[i]; const object = getNode(node); if (object instanceof THREE.Object3D) scene2.add(object); if (node.name === "WorldInfo") scene2.userData.worldInfo = object; } return scene2; } function buildNodeMap(node) { if (node.DEF) { nodeMap[node.DEF] = node; } const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; if (field.type === "node") { const fieldValues = field.values; for (let j = 0, jl = fieldValues.length; j < jl; j++) { buildNodeMap(fieldValues[j]); } } } } function getNode(node) { if (node.USE) { return resolveUSE(node.USE); } if (node.build !== void 0) return node.build; node.build = buildNode(node); return node.build; } function buildNode(node) { const nodeName = node.name; let build; switch (nodeName) { case "Group": case "Transform": case "Collision": build = buildGroupingNode(node); break; case "Background": build = buildBackgroundNode(node); break; case "Shape": build = buildShapeNode(node); break; case "Appearance": build = buildAppearanceNode(node); break; case "Material": build = buildMaterialNode(node); break; case "ImageTexture": build = buildImageTextureNode(node); break; case "PixelTexture": build = buildPixelTextureNode(node); break; case "TextureTransform": build = buildTextureTransformNode(node); break; case "IndexedFaceSet": build = buildIndexedFaceSetNode(node); break; case "IndexedLineSet": build = buildIndexedLineSetNode(node); break; case "PointSet": build = buildPointSetNode(node); break; case "Box": build = buildBoxNode(node); break; case "Cone": build = buildConeNode(node); break; case "Cylinder": build = buildCylinderNode(node); break; case "Sphere": build = buildSphereNode(node); break; case "ElevationGrid": build = buildElevationGridNode(node); break; case "Extrusion": build = buildExtrusionNode(node); break; case "Color": case "Coordinate": case "Normal": case "TextureCoordinate": build = buildGeometricNode(node); break; case "WorldInfo": build = buildWorldInfoNode(node); break; case "Anchor": case "Billboard": case "Inline": case "LOD": case "Switch": case "AudioClip": case "DirectionalLight": case "PointLight": case "Script": case "Sound": case "SpotLight": case "CylinderSensor": case "PlaneSensor": case "ProximitySensor": case "SphereSensor": case "TimeSensor": case "TouchSensor": case "VisibilitySensor": case "Text": case "FontStyle": case "MovieTexture": case "ColorInterpolator": case "CoordinateInterpolator": case "NormalInterpolator": case "OrientationInterpolator": case "PositionInterpolator": case "ScalarInterpolator": case "Fog": case "NavigationInfo": case "Viewpoint": break; default: console.warn("THREE.VRMLLoader: Unknown node:", nodeName); break; } if (build !== void 0 && node.DEF !== void 0 && build.hasOwnProperty("name") === true) { build.name = node.DEF; } return build; } function buildGroupingNode(node) { const object = new THREE.Group(); const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "bboxCenter": break; case "bboxSize": break; case "center": break; case "children": parseFieldChildren(fieldValues, object); break; case "collide": break; case "rotation": const axis = new THREE.Vector3(fieldValues[0], fieldValues[1], fieldValues[2]).normalize(); const angle = fieldValues[3]; object.quaternion.setFromAxisAngle(axis, angle); break; case "scale": object.scale.set(fieldValues[0], fieldValues[1], fieldValues[2]); break; case "scaleOrientation": break; case "translation": object.position.set(fieldValues[0], fieldValues[1], fieldValues[2]); break; case "proxy": break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } return object; } function buildBackgroundNode(node) { const group = new THREE.Group(); let groundAngle, groundColor; let skyAngle, skyColor; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "groundAngle": groundAngle = fieldValues; break; case "groundColor": groundColor = fieldValues; break; case "backUrl": break; case "bottomUrl": break; case "frontUrl": break; case "leftUrl": break; case "rightUrl": break; case "topUrl": break; case "skyAngle": skyAngle = fieldValues; break; case "skyColor": skyColor = fieldValues; break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } const radius = 1e4; if (skyColor) { const skyGeometry = new THREE.SphereGeometry(radius, 32, 16); const skyMaterial = new THREE.MeshBasicMaterial({ fog: false, side: THREE.BackSide, depthWrite: false, depthTest: false }); if (skyColor.length > 3) { paintFaces(skyGeometry, radius, skyAngle, toColorArray(skyColor), true); skyMaterial.vertexColors = true; } else { skyMaterial.color.setRGB(skyColor[0], skyColor[1], skyColor[2]); } const sky = new THREE.Mesh(skyGeometry, skyMaterial); group.add(sky); } if (groundColor) { if (groundColor.length > 0) { const groundGeometry = new THREE.SphereGeometry(radius, 32, 16, 0, 2 * Math.PI, 0.5 * Math.PI, 1.5 * Math.PI); const groundMaterial = new THREE.MeshBasicMaterial({ fog: false, side: THREE.BackSide, vertexColors: true, depthWrite: false, depthTest: false }); paintFaces(groundGeometry, radius, groundAngle, toColorArray(groundColor), false); const ground = new THREE.Mesh(groundGeometry, groundMaterial); group.add(ground); } } group.renderOrder = -Infinity; return group; } function buildShapeNode(node) { const fields = node.fields; let material = new THREE.MeshBasicMaterial({ color: 0 }); let geometry; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "appearance": if (fieldValues[0] !== null) { material = getNode(fieldValues[0]); } break; case "geometry": if (fieldValues[0] !== null) { geometry = getNode(fieldValues[0]); } break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } let object; if (geometry && geometry.attributes.position) { const type = geometry._type; if (type === "points") { const pointsMaterial = new THREE.PointsMaterial({ color: 16777215 }); if (geometry.attributes.color !== void 0) { pointsMaterial.vertexColors = true; } else { if (material.isMeshPhongMaterial) { pointsMaterial.color.copy(material.emissive); } } object = new THREE.Points(geometry, pointsMaterial); } else if (type === "line") { const lineMaterial = new THREE.LineBasicMaterial({ color: 16777215 }); if (geometry.attributes.color !== void 0) { lineMaterial.vertexColors = true; } else { if (material.isMeshPhongMaterial) { lineMaterial.color.copy(material.emissive); } } object = new THREE.LineSegments(geometry, lineMaterial); } else { if (geometry._solid !== void 0) { material.side = geometry._solid ? THREE.FrontSide : THREE.DoubleSide; } if (geometry.attributes.color !== void 0) { material.vertexColors = true; } object = new THREE.Mesh(geometry, material); } } else { object = new THREE.Object3D(); object.visible = false; } return object; } function buildAppearanceNode(node) { let material = new THREE.MeshPhongMaterial(); let transformData; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "material": if (fieldValues[0] !== null) { const materialData = getNode(fieldValues[0]); if (materialData.diffuseColor) material.color.copy(materialData.diffuseColor); if (materialData.emissiveColor) material.emissive.copy(materialData.emissiveColor); if (materialData.shininess) material.shininess = materialData.shininess; if (materialData.specularColor) material.specular.copy(materialData.specularColor); if (materialData.transparency) material.opacity = 1 - materialData.transparency; if (materialData.transparency > 0) material.transparent = true; } else { material = new THREE.MeshBasicMaterial({ color: 0 }); } break; case "texture": const textureNode = fieldValues[0]; if (textureNode !== null) { if (textureNode.name === "ImageTexture" || textureNode.name === "PixelTexture") { material.map = getNode(textureNode); } } break; case "textureTransform": if (fieldValues[0] !== null) { transformData = getNode(fieldValues[0]); } break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } if (material.map) { if (material.map.__type) { switch (material.map.__type) { case TEXTURE_TYPE.INTENSITY_ALPHA: material.opacity = 1; break; case TEXTURE_TYPE.RGB: material.color.set(16777215); break; case TEXTURE_TYPE.RGBA: material.color.set(16777215); material.opacity = 1; break; } delete material.map.__type; } if (transformData) { material.map.center.copy(transformData.center); material.map.rotation = transformData.rotation; material.map.repeat.copy(transformData.scale); material.map.offset.copy(transformData.translation); } } return material; } function buildMaterialNode(node) { const materialData = {}; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "ambientIntensity": break; case "diffuseColor": materialData.diffuseColor = new THREE.Color(fieldValues[0], fieldValues[1], fieldValues[2]); break; case "emissiveColor": materialData.emissiveColor = new THREE.Color(fieldValues[0], fieldValues[1], fieldValues[2]); break; case "shininess": materialData.shininess = fieldValues[0]; break; case "specularColor": materialData.emissiveColor = new THREE.Color(fieldValues[0], fieldValues[1], fieldValues[2]); break; case "transparency": materialData.transparency = fieldValues[0]; break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } return materialData; } function parseHexColor(hex, textureType, color) { let value; switch (textureType) { case TEXTURE_TYPE.INTENSITY: value = parseInt(hex); color.r = value; color.g = value; color.b = value; color.a = 1; break; case TEXTURE_TYPE.INTENSITY_ALPHA: value = parseInt("0x" + hex.substring(2, 4)); color.r = value; color.g = value; color.b = value; color.a = parseInt("0x" + hex.substring(4, 6)); break; case TEXTURE_TYPE.RGB: color.r = parseInt("0x" + hex.substring(2, 4)); color.g = parseInt("0x" + hex.substring(4, 6)); color.b = parseInt("0x" + hex.substring(6, 8)); color.a = 1; break; case TEXTURE_TYPE.RGBA: color.r = parseInt("0x" + hex.substring(2, 4)); color.g = parseInt("0x" + hex.substring(4, 6)); color.b = parseInt("0x" + hex.substring(6, 8)); color.a = parseInt("0x" + hex.substring(8, 10)); break; } } function getTextureType(num_components) { let type; switch (num_components) { case 1: type = TEXTURE_TYPE.INTENSITY; break; case 2: type = TEXTURE_TYPE.INTENSITY_ALPHA; break; case 3: type = TEXTURE_TYPE.RGB; break; case 4: type = TEXTURE_TYPE.RGBA; break; } return type; } function buildPixelTextureNode(node) { let texture; let wrapS = THREE.RepeatWrapping; let wrapT = THREE.RepeatWrapping; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "image": const width = fieldValues[0]; const height = fieldValues[1]; const num_components = fieldValues[2]; const textureType = getTextureType(num_components); const data2 = new Uint8Array(4 * width * height); const color = { r: 0, g: 0, b: 0, a: 0 }; for (let j = 3, k = 0, jl = fieldValues.length; j < jl; j++, k++) { parseHexColor(fieldValues[j], textureType, color); const stride = k * 4; data2[stride + 0] = color.r; data2[stride + 1] = color.g; data2[stride + 2] = color.b; data2[stride + 3] = color.a; } texture = new THREE.DataTexture(data2, width, height); texture.needsUpdate = true; texture.__type = textureType; break; case "repeatS": if (fieldValues[0] === false) wrapS = THREE.ClampToEdgeWrapping; break; case "repeatT": if (fieldValues[0] === false) wrapT = THREE.ClampToEdgeWrapping; break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } if (texture) { texture.wrapS = wrapS; texture.wrapT = wrapT; } return texture; } function buildImageTextureNode(node) { let texture; let wrapS = THREE.RepeatWrapping; let wrapT = THREE.RepeatWrapping; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "url": const url = fieldValues[0]; if (url) texture = textureLoader.load(url); break; case "repeatS": if (fieldValues[0] === false) wrapS = THREE.ClampToEdgeWrapping; break; case "repeatT": if (fieldValues[0] === false) wrapT = THREE.ClampToEdgeWrapping; break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } if (texture) { texture.wrapS = wrapS; texture.wrapT = wrapT; } return texture; } function buildTextureTransformNode(node) { const transformData = { center: new THREE.Vector2(), rotation: new THREE.Vector2(), scale: new THREE.Vector2(), translation: new THREE.Vector2() }; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "center": transformData.center.set(fieldValues[0], fieldValues[1]); break; case "rotation": transformData.rotation = fieldValues[0]; break; case "scale": transformData.scale.set(fieldValues[0], fieldValues[1]); break; case "translation": transformData.translation.set(fieldValues[0], fieldValues[1]); break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } return transformData; } function buildGeometricNode(node) { return node.fields[0].values; } function buildWorldInfoNode(node) { const worldInfo = {}; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "title": worldInfo.title = fieldValues[0]; break; case "info": worldInfo.info = fieldValues; break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } return worldInfo; } function buildIndexedFaceSetNode(node) { let color, coord, normal, texCoord; let ccw = true, solid = true, creaseAngle = 0; let colorIndex, coordIndex, normalIndex, texCoordIndex; let colorPerVertex = true, normalPerVertex = true; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "color": const colorNode = fieldValues[0]; if (colorNode !== null) { color = getNode(colorNode); } break; case "coord": const coordNode = fieldValues[0]; if (coordNode !== null) { coord = getNode(coordNode); } break; case "normal": const normalNode = fieldValues[0]; if (normalNode !== null) { normal = getNode(normalNode); } break; case "texCoord": const texCoordNode = fieldValues[0]; if (texCoordNode !== null) { texCoord = getNode(texCoordNode); } break; case "ccw": ccw = fieldValues[0]; break; case "colorIndex": colorIndex = fieldValues; break; case "colorPerVertex": colorPerVertex = fieldValues[0]; break; case "convex": break; case "coordIndex": coordIndex = fieldValues; break; case "creaseAngle": creaseAngle = fieldValues[0]; break; case "normalIndex": normalIndex = fieldValues; break; case "normalPerVertex": normalPerVertex = fieldValues[0]; break; case "solid": solid = fieldValues[0]; break; case "texCoordIndex": texCoordIndex = fieldValues; break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } if (coordIndex === void 0) { console.warn("THREE.VRMLLoader: Missing coordIndex."); return new THREE.BufferGeometry(); } const triangulatedCoordIndex = triangulateFaceIndex(coordIndex, ccw); let colorAttribute; let normalAttribute; let uvAttribute; if (color) { if (colorPerVertex === true) { if (colorIndex && colorIndex.length > 0) { const triangulatedColorIndex = triangulateFaceIndex(colorIndex, ccw); colorAttribute = computeAttributeFromIndexedData(triangulatedCoordIndex, triangulatedColorIndex, color, 3); } else { colorAttribute = toNonIndexedAttribute(triangulatedCoordIndex, new THREE.Float32BufferAttribute(color, 3)); } } else { if (colorIndex && colorIndex.length > 0) { const flattenFaceColors = flattenData(color, colorIndex); const triangulatedFaceColors = triangulateFaceData(flattenFaceColors, coordIndex); colorAttribute = computeAttributeFromFaceData(triangulatedCoordIndex, triangulatedFaceColors); } else { const triangulatedFaceColors = triangulateFaceData(color, coordIndex); colorAttribute = computeAttributeFromFaceData(triangulatedCoordIndex, triangulatedFaceColors); } } } if (normal) { if (normalPerVertex === true) { if (normalIndex && normalIndex.length > 0) { const triangulatedNormalIndex = triangulateFaceIndex(normalIndex, ccw); normalAttribute = computeAttributeFromIndexedData( triangulatedCoordIndex, triangulatedNormalIndex, normal, 3 ); } else { normalAttribute = toNonIndexedAttribute(triangulatedCoordIndex, new THREE.Float32BufferAttribute(normal, 3)); } } else { if (normalIndex && normalIndex.length > 0) { const flattenFaceNormals = flattenData(normal, normalIndex); const triangulatedFaceNormals = triangulateFaceData(flattenFaceNormals, coordIndex); normalAttribute = computeAttributeFromFaceData(triangulatedCoordIndex, triangulatedFaceNormals); } else { const triangulatedFaceNormals = triangulateFaceData(normal, coordIndex); normalAttribute = computeAttributeFromFaceData(triangulatedCoordIndex, triangulatedFaceNormals); } } } else { normalAttribute = computeNormalAttribute(triangulatedCoordIndex, coord, creaseAngle); } if (texCoord) { if (texCoordIndex && texCoordIndex.length > 0) { const triangulatedTexCoordIndex = triangulateFaceIndex(texCoordIndex, ccw); uvAttribute = computeAttributeFromIndexedData(triangulatedCoordIndex, triangulatedTexCoordIndex, texCoord, 2); } else { uvAttribute = toNonIndexedAttribute(triangulatedCoordIndex, new THREE.Float32BufferAttribute(texCoord, 2)); } } const geometry = new THREE.BufferGeometry(); const positionAttribute = toNonIndexedAttribute(triangulatedCoordIndex, new THREE.Float32BufferAttribute(coord, 3)); geometry.setAttribute("position", positionAttribute); geometry.setAttribute("normal", normalAttribute); if (colorAttribute) geometry.setAttribute("color", colorAttribute); if (uvAttribute) geometry.setAttribute("uv", uvAttribute); geometry._solid = solid; geometry._type = "mesh"; return geometry; } function buildIndexedLineSetNode(node) { let color, coord; let colorIndex, coordIndex; let colorPerVertex = true; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "color": const colorNode = fieldValues[0]; if (colorNode !== null) { color = getNode(colorNode); } break; case "coord": const coordNode = fieldValues[0]; if (coordNode !== null) { coord = getNode(coordNode); } break; case "colorIndex": colorIndex = fieldValues; break; case "colorPerVertex": colorPerVertex = fieldValues[0]; break; case "coordIndex": coordIndex = fieldValues; break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } let colorAttribute; const expandedLineIndex = expandLineIndex(coordIndex); if (color) { if (colorPerVertex === true) { if (colorIndex.length > 0) { const expandedColorIndex = expandLineIndex(colorIndex); colorAttribute = computeAttributeFromIndexedData(expandedLineIndex, expandedColorIndex, color, 3); } else { colorAttribute = toNonIndexedAttribute(expandedLineIndex, new THREE.Float32BufferAttribute(color, 3)); } } else { if (colorIndex.length > 0) { const flattenLineColors = flattenData(color, colorIndex); const expandedLineColors = expandLineData(flattenLineColors, coordIndex); colorAttribute = computeAttributeFromLineData(expandedLineIndex, expandedLineColors); } else { const expandedLineColors = expandLineData(color, coordIndex); colorAttribute = computeAttributeFromLineData(expandedLineIndex, expandedLineColors); } } } const geometry = new THREE.BufferGeometry(); const positionAttribute = toNonIndexedAttribute(expandedLineIndex, new THREE.Float32BufferAttribute(coord, 3)); geometry.setAttribute("position", positionAttribute); if (colorAttribute) geometry.setAttribute("color", colorAttribute); geometry._type = "line"; return geometry; } function buildPointSetNode(node) { let color, coord; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "color": const colorNode = fieldValues[0]; if (colorNode !== null) { color = getNode(colorNode); } break; case "coord": const coordNode = fieldValues[0]; if (coordNode !== null) { coord = getNode(coordNode); } break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } const geometry = new THREE.BufferGeometry(); geometry.setAttribute("position", new THREE.Float32BufferAttribute(coord, 3)); if (color) geometry.setAttribute("color", new THREE.Float32BufferAttribute(color, 3)); geometry._type = "points"; return geometry; } function buildBoxNode(node) { const size = new THREE.Vector3(2, 2, 2); const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "size": size.x = fieldValues[0]; size.y = fieldValues[1]; size.z = fieldValues[2]; break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } const geometry = new THREE.BoxGeometry(size.x, size.y, size.z); return geometry; } function buildConeNode(node) { let radius = 1, height = 2, openEnded = false; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "bottom": openEnded = !fieldValues[0]; break; case "bottomRadius": radius = fieldValues[0]; break; case "height": height = fieldValues[0]; break; case "side": break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } const geometry = new THREE.ConeGeometry(radius, height, 16, 1, openEnded); return geometry; } function buildCylinderNode(node) { let radius = 1, height = 2; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "bottom": break; case "radius": radius = fieldValues[0]; break; case "height": height = fieldValues[0]; break; case "side": break; case "top": break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } const geometry = new THREE.CylinderGeometry(radius, radius, height, 16, 1); return geometry; } function buildSphereNode(node) { let radius = 1; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "radius": radius = fieldValues[0]; break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } const geometry = new THREE.SphereGeometry(radius, 16, 16); return geometry; } function buildElevationGridNode(node) { let color; let normal; let texCoord; let height; let colorPerVertex = true; let normalPerVertex = true; let solid = true; let ccw = true; let creaseAngle = 0; let xDimension = 2; let zDimension = 2; let xSpacing = 1; let zSpacing = 1; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "color": const colorNode = fieldValues[0]; if (colorNode !== null) { color = getNode(colorNode); } break; case "normal": const normalNode = fieldValues[0]; if (normalNode !== null) { normal = getNode(normalNode); } break; case "texCoord": const texCoordNode = fieldValues[0]; if (texCoordNode !== null) { texCoord = getNode(texCoordNode); } break; case "height": height = fieldValues; break; case "ccw": ccw = fieldValues[0]; break; case "colorPerVertex": colorPerVertex = fieldValues[0]; break; case "creaseAngle": creaseAngle = fieldValues[0]; break; case "normalPerVertex": normalPerVertex = fieldValues[0]; break; case "solid": solid = fieldValues[0]; break; case "xDimension": xDimension = fieldValues[0]; break; case "xSpacing": xSpacing = fieldValues[0]; break; case "zDimension": zDimension = fieldValues[0]; break; case "zSpacing": zSpacing = fieldValues[0]; break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } const vertices = []; const normals = []; const colors = []; const uvs = []; for (let i = 0; i < zDimension; i++) { for (let j = 0; j < xDimension; j++) { const index = i * xDimension + j; const x = xSpacing * i; const y = height[index]; const z = zSpacing * j; vertices.push(x, y, z); if (color && colorPerVertex === true) { const r = color[index * 3 + 0]; const g = color[index * 3 + 1]; const b = color[index * 3 + 2]; colors.push(r, g, b); } if (normal && normalPerVertex === true) { const xn = normal[index * 3 + 0]; const yn = normal[index * 3 + 1]; const zn = normal[index * 3 + 2]; normals.push(xn, yn, zn); } if (texCoord) { const s = texCoord[index * 2 + 0]; const t = texCoord[index * 2 + 1]; uvs.push(s, t); } else { uvs.push(i / (xDimension - 1), j / (zDimension - 1)); } } } const indices = []; for (let i = 0; i < xDimension - 1; i++) { for (let j = 0; j < zDimension - 1; j++) { const a = i + j * xDimension; const b = i + (j + 1) * xDimension; const c = i + 1 + (j + 1) * xDimension; const d = i + 1 + j * xDimension; if (ccw === true) { indices.push(a, c, b); indices.push(c, a, d); } else { indices.push(a, b, c); indices.push(c, d, a); } } } const positionAttribute = toNonIndexedAttribute(indices, new THREE.Float32BufferAttribute(vertices, 3)); const uvAttribute = toNonIndexedAttribute(indices, new THREE.Float32BufferAttribute(uvs, 2)); let colorAttribute; let normalAttribute; if (color) { if (colorPerVertex === false) { for (let i = 0; i < xDimension - 1; i++) { for (let j = 0; j < zDimension - 1; j++) { const index = i + j * (xDimension - 1); const r = color[index * 3 + 0]; const g = color[index * 3 + 1]; const b = color[index * 3 + 2]; colors.push(r, g, b); colors.push(r, g, b); colors.push(r, g, b); colors.push(r, g, b); colors.push(r, g, b); colors.push(r, g, b); } } colorAttribute = new THREE.Float32BufferAttribute(colors, 3); } else { colorAttribute = toNonIndexedAttribute(indices, new THREE.Float32BufferAttribute(colors, 3)); } } if (normal) { if (normalPerVertex === false) { for (let i = 0; i < xDimension - 1; i++) { for (let j = 0; j < zDimension - 1; j++) { const index = i + j * (xDimension - 1); const xn = normal[index * 3 + 0]; const yn = normal[index * 3 + 1]; const zn = normal[index * 3 + 2]; normals.push(xn, yn, zn); normals.push(xn, yn, zn); normals.push(xn, yn, zn); normals.push(xn, yn, zn); normals.push(xn, yn, zn); normals.push(xn, yn, zn); } } normalAttribute = new THREE.Float32BufferAttribute(normals, 3); } else { normalAttribute = toNonIndexedAttribute(indices, new THREE.Float32BufferAttribute(normals, 3)); } } else { normalAttribute = computeNormalAttribute(indices, vertices, creaseAngle); } const geometry = new THREE.BufferGeometry(); geometry.setAttribute("position", positionAttribute); geometry.setAttribute("normal", normalAttribute); geometry.setAttribute("uv", uvAttribute); if (colorAttribute) geometry.setAttribute("color", colorAttribute); geometry._solid = solid; geometry._type = "mesh"; return geometry; } function buildExtrusionNode(node) { let crossSection = [1, 1, 1, -1, -1, -1, -1, 1, 1, 1]; let spine = [0, 0, 0, 0, 1, 0]; let scale; let orientation; let beginCap = true; let ccw = true; let creaseAngle = 0; let endCap = true; let solid = true; const fields = node.fields; for (let i = 0, l = fields.length; i < l; i++) { const field = fields[i]; const fieldName = field.name; const fieldValues = field.values; switch (fieldName) { case "beginCap": beginCap = fieldValues[0]; break; case "ccw": ccw = fieldValues[0]; break; case "convex": break; case "creaseAngle": creaseAngle = fieldValues[0]; break; case "crossSection": crossSection = fieldValues; break; case "endCap": endCap = fieldValues[0]; break; case "orientation": orientation = fieldValues; break; case "scale": scale = fieldValues; break; case "solid": solid = fieldValues[0]; break; case "spine": spine = fieldValues; break; default: console.warn("THREE.VRMLLoader: Unknown field:", fieldName); break; } } const crossSectionClosed = crossSection[0] === crossSection[crossSection.length - 2] && crossSection[1] === crossSection[crossSection.length - 1]; const vertices = []; const spineVector = new THREE.Vector3(); const scaling = new THREE.Vector3(); const axis = new THREE.Vector3(); const vertex = new THREE.Vector3(); const quaternion = new THREE.Quaternion(); for (let i = 0, j = 0, o = 0, il = spine.length; i < il; i += 3, j += 2, o += 4) { spineVector.fromArray(spine, i); scaling.x = scale ? scale[j + 0] : 1; scaling.y = 1; scaling.z = scale ? scale[j + 1] : 1; axis.x = orientation ? orientation[o + 0] : 0; axis.y = orientation ? orientation[o + 1] : 0; axis.z = orientation ? orientation[o + 2] : 1; const angle = orientation ? orientation[o + 3] : 0; for (let k = 0, kl = crossSection.length; k < kl; k += 2) { vertex.x = crossSection[k + 0]; vertex.y = 0; vertex.z = crossSection[k + 1]; vertex.multiply(scaling); quaternion.setFromAxisAngle(axis, angle); vertex.applyQuaternion(quaternion); vertex.add(spineVector); vertices.push(vertex.x, vertex.y, vertex.z); } } const indices = []; const spineCount = spine.length / 3; const crossSectionCount = crossSection.length / 2; for (let i = 0; i < spineCount - 1; i++) { for (let j = 0; j < crossSectionCount - 1; j++) { const a = j + i * crossSectionCount; let b = j + 1 + i * crossSectionCount; const c = j + (i + 1) * crossSectionCount; let d = j + 1 + (i + 1) * crossSectionCount; if (j === crossSectionCount - 2 && crossSectionClosed === true) { b = i * crossSectionCount; d = (i + 1) * crossSectionCount; } if (ccw === true) { indices.push(a, b, c); indices.push(c, b, d); } else { indices.push(a, c, b); indices.push(c, d, b); } } } if (beginCap === true || endCap === true) { const contour = []; for (let i = 0, l = crossSection.length; i < l; i += 2) { contour.push(new THREE.Vector2(crossSection[i], crossSection[i + 1])); } const faces = THREE.ShapeUtils.triangulateShape(contour, []); const capIndices = []; for (let i = 0, l = faces.length; i < l; i++) { const face = faces[i]; capIndices.push(face[0], face[1], face[2]); } if (beginCap === true) { for (let i = 0, l = capIndices.length; i < l; i += 3) { if (ccw === true) { indices.push(capIndices[i + 0], capIndices[i + 1], capIndices[i + 2]); } else { indices.push(capIndices[i + 0], capIndices[i + 2], capIndices[i + 1]); } } } if (endCap === true) { const indexOffset = crossSectionCount * (spineCount - 1); for (let i = 0, l = capIndices.length; i < l; i += 3) { if (ccw === true) { indices.push( indexOffset + capIndices[i + 0], indexOffset + capIndices[i + 2], indexOffset + capIndices[i + 1] ); } else { indices.push( indexOffset + capIndices[i + 0], indexOffset + capIndices[i + 1], indexOffset + capIndices[i + 2] ); } } } } const positionAttribute = toNonIndexedAttribute(indices, new THREE.Float32BufferAttribute(vertices, 3)); const normalAttribute = computeNormalAttribute(indices, vertices, creaseAngle); const geometry = new THREE.BufferGeometry(); geometry.setAttribute("position", positionAttribute); geometry.setAttribute("normal", normalAttribute); geometry._solid = solid; geometry._type = "mesh"; return geometry; } function resolveUSE(identifier) { const node = nodeMap[identifier]; const build = getNode(node); return build.isObject3D || build.isMaterial ? build.clone() : build; } function parseFieldChildren(children, owner) { for (let i = 0, l = children.length; i < l; i++) { const object = getNode(children[i]); if (object instanceof THREE.Object3D) owner.add(object); } } function triangulateFaceIndex(index, ccw) { const indices = []; let start = 0; for (let i = 0, l = index.length; i < l; i++) { const i1 = index[start]; const i2 = index[i + (ccw ? 1 : 2)]; const i3 = index[i + (ccw ? 2 : 1)]; indices.push(i1, i2, i3); if (index[i + 3] === -1 || i + 3 >= l) { i += 3; start = i + 1; } } return indices; } function triangulateFaceData(data2, index) { const triangulatedData = []; let start = 0; for (let i = 0, l = index.length; i < l; i++) { const stride = start * 3; const x = data2[stride]; const y = data2[stride + 1]; const z = data2[stride + 2]; triangulatedData.push(x, y, z); if (index[i + 3] === -1 || i + 3 >= l) { i += 3; start++; } } return triangulatedData; } function flattenData(data2, index) { const flattenData2 = []; for (let i = 0, l = index.length; i < l; i++) { const i1 = index[i]; const stride = i1 * 3; const x = data2[stride]; const y = data2[stride + 1]; const z = data2[stride + 2]; flattenData2.push(x, y, z); } return flattenData2; } function expandLineIndex(index) { const indices = []; for (let i = 0, l = index.length; i < l; i++) { const i1 = index[i]; const i2 = index[i + 1]; indices.push(i1, i2); if (index[i + 2] === -1 || i + 2 >= l) { i += 2; } } return indices; } function expandLineData(data2, index) { const triangulatedData = []; let start = 0; for (let i = 0, l = index.length; i < l; i++) { const stride = start * 3; const x = data2[stride]; const y = data2[stride + 1]; const z = data2[stride + 2]; triangulatedData.push(x, y, z); if (index[i + 2] === -1 || i + 2 >= l) { i += 2; start++; } } return triangulatedData; } const vA = new THREE.Vector3(); const vB = new THREE.Vector3(); const vC = new THREE.Vector3(); const uvA = new THREE.Vector2(); const uvB = new THREE.Vector2(); const uvC = new THREE.Vector2(); function computeAttributeFromIndexedData(coordIndex, index, data2, itemSize) { const array = []; for (let i = 0, l = coordIndex.length; i < l; i += 3) { const a = index[i]; const b = index[i + 1]; const c = index[i + 2]; if (itemSize === 2) { uvA.fromArray(data2, a * itemSize); uvB.fromArray(data2, b * itemSize); uvC.fromArray(data2, c * itemSize); array.push(uvA.x, uvA.y); array.push(uvB.x, uvB.y); array.push(uvC.x, uvC.y); } else { vA.fromArray(data2, a * itemSize); vB.fromArray(data2, b * itemSize); vC.fromArray(data2, c * itemSize); array.push(vA.x, vA.y, vA.z); array.push(vB.x, vB.y, vB.z); array.push(vC.x, vC.y, vC.z); } } return new THREE.Float32BufferAttribute(array, itemSize); } function computeAttributeFromFaceData(index, faceData) { const array = []; for (let i = 0, j = 0, l = index.length; i < l; i += 3, j++) { vA.fromArray(faceData, j * 3); array.push(vA.x, vA.y, vA.z); array.push(vA.x, vA.y, vA.z); array.push(vA.x, vA.y, vA.z); } return new THREE.Float32BufferAttribute(array, 3); } function computeAttributeFromLineData(index, lineData) { const array = []; for (let i = 0, j = 0, l = index.length; i < l; i += 2, j++) { vA.fromArray(lineData, j * 3); array.push(vA.x, vA.y, vA.z); array.push(vA.x, vA.y, vA.z); } return new THREE.Float32BufferAttribute(array, 3); } function toNonIndexedAttribute(indices, attribute) { const array = attribute.array; const itemSize = attribute.itemSize; const array2 = new array.constructor(indices.length * itemSize); let index = 0, index2 = 0; for (let i = 0, l = indices.length; i < l; i++) { index = indices[i] * itemSize; for (let j = 0; j < itemSize; j++) { array2[index2++] = array[index++]; } } return new THREE.Float32BufferAttribute(array2, itemSize); } const ab = new THREE.Vector3(); const cb = new THREE.Vector3(); function computeNormalAttribute(index, coord, creaseAngle) { const faces = []; const vertexNormals = {}; for (let i = 0, l = index.length; i < l; i += 3) { const a = index[i]; const b = index[i + 1]; const c = index[i + 2]; const face = new Face(a, b, c); vA.fromArray(coord, a * 3); vB.fromArray(coord, b * 3); vC.fromArray(coord, c * 3); cb.subVectors(vC, vB); ab.subVectors(vA, vB); cb.cross(ab); cb.normalize(); face.normal.copy(cb); if (vertexNormals[a] === void 0) vertexNormals[a] = []; if (vertexNormals[b] === void 0) vertexNormals[b] = []; if (vertexNormals[c] === void 0) vertexNormals[c] = []; vertexNormals[a].push(face.normal); vertexNormals[b].push(face.normal); vertexNormals[c].push(face.normal); faces.push(face); } const normals = []; for (let i = 0, l = faces.length; i < l; i++) { const face = faces[i]; const nA = weightedNormal(vertexNormals[face.a], face.normal, creaseAngle); const nB = weightedNormal(vertexNormals[face.b], face.normal, creaseAngle); const nC = weightedNormal(vertexNormals[face.c], face.normal, creaseAngle); vA.fromArray(coord, face.a * 3); vB.fromArray(coord, face.b * 3); vC.fromArray(coord, face.c * 3); normals.push(nA.x, nA.y, nA.z); normals.push(nB.x, nB.y, nB.z); normals.push(nC.x, nC.y, nC.z); } return new THREE.Float32BufferAttribute(normals, 3); } function weightedNormal(normals, vector, creaseAngle) { const normal = new THREE.Vector3(); if (creaseAngle === 0) { normal.copy(vector); } else { for (let i = 0, l = normals.length; i < l; i++) { if (normals[i].angleTo(vector) < creaseAngle) { normal.add(normals[i]); } } } return normal.normalize(); } function toColorArray(colors) { const array = []; for (let i = 0, l = colors.length; i < l; i += 3) { array.push(new THREE.Color(colors[i], colors[i + 1], colors[i + 2])); } return array; } function paintFaces(geometry, radius, angles, colors, topDown) { const thresholds = []; const startAngle = topDown === true ? 0 : Math.PI; for (let i = 0, l = colors.length; i < l; i++) { let angle = i === 0 ? 0 : angles[i - 1]; angle = topDown === true ? angle : startAngle - angle; const point = new THREE.Vector3(); point.setFromSphericalCoords(radius, angle, 0); thresholds.push(point); } const indices = geometry.index; const positionAttribute = geometry.attributes.position; const colorAttribute = new THREE.BufferAttribute(new Float32Array(geometry.attributes.position.count * 3), 3); const position = new THREE.Vector3(); const color = new THREE.Color(); for (let i = 0; i < indices.count; i++) { const index = indices.getX(i); position.fromBufferAttribute(positionAttribute, index); let thresholdIndexA, thresholdIndexB; let t = 1; for (let j = 1; j < thresholds.length; j++) { thresholdIndexA = j - 1; thresholdIndexB = j; const thresholdA = thresholds[thresholdIndexA]; const thresholdB = thresholds[thresholdIndexB]; if (topDown === true) { if (position.y <= thresholdA.y && position.y > thresholdB.y) { t = Math.abs(thresholdA.y - position.y) / Math.abs(thresholdA.y - thresholdB.y); break; } } else { if (position.y >= thresholdA.y && position.y < thresholdB.y) { t = Math.abs(thresholdA.y - position.y) / Math.abs(thresholdA.y - thresholdB.y); break; } } } const colorA = colors[thresholdIndexA]; const colorB = colors[thresholdIndexB]; color.copy(colorA).lerp(colorB, t); colorAttribute.setXYZ(index, color.r, color.g, color.b); } geometry.setAttribute("color", colorAttribute); } const textureLoader = new THREE.TextureLoader(this.manager); textureLoader.setPath(this.resourcePath || path).setCrossOrigin(this.crossOrigin); if (data.indexOf("#VRML V2.0") === -1) { throw Error("THREE.VRMLLexer: Version of VRML asset not supported."); } const tree = generateVRMLTree(data); const scene = parseTree(tree); return scene; } } class VRMLLexer { constructor(tokens) { this.lexer = new chevrotain.Lexer(tokens); } lex(inputText) { const lexingResult = this.lexer.tokenize(inputText); if (lexingResult.errors.length > 0) { console.error(lexingResult.errors); throw Error("THREE.VRMLLexer: Lexing errors detected."); } return lexingResult; } } class VRMLParser extends chevrotain.CstParser { constructor(tokenVocabulary) { super(tokenVocabulary); const $ = this; const Version = tokenVocabulary["Version"]; const LCurly = tokenVocabulary["LCurly"]; const RCurly = tokenVocabulary["RCurly"]; const LSquare = tokenVocabulary["LSquare"]; const RSquare = tokenVocabulary["RSquare"]; const Identifier = tokenVocabulary["Identifier"]; const RouteIdentifier = tokenVocabulary["RouteIdentifier"]; const StringLiteral = tokenVocabulary["StringLiteral"]; const HexLiteral = tokenVocabulary["HexLiteral"]; const NumberLiteral = tokenVocabulary["NumberLiteral"]; const TrueLiteral = tokenVocabulary["TrueLiteral"]; const FalseLiteral = tokenVocabulary["FalseLiteral"]; const NullLiteral = tokenVocabulary["NullLiteral"]; const DEF = tokenVocabulary["DEF"]; const USE = tokenVocabulary["USE"]; const ROUTE = tokenVocabulary["ROUTE"]; const TO = tokenVocabulary["TO"]; const NodeName = tokenVocabulary["NodeName"]; $.RULE("vrml", function() { $.SUBRULE($.version); $.AT_LEAST_ONE(function() { $.SUBRULE($.node); }); $.MANY(function() { $.SUBRULE($.route); }); }); $.RULE("version", function() { $.CONSUME(Version); }); $.RULE("node", function() { $.OPTION(function() { $.SUBRULE($.def); }); $.CONSUME(NodeName); $.CONSUME(LCurly); $.MANY(function() { $.SUBRULE($.field); }); $.CONSUME(RCurly); }); $.RULE("field", function() { $.CONSUME(Identifier); $.OR2([ { ALT: function() { $.SUBRULE($.singleFieldValue); } }, { ALT: function() { $.SUBRULE($.multiFieldValue); } } ]); }); $.RULE("def", function() { $.CONSUME(DEF); $.OR([ { ALT: function() { $.CONSUME(Identifier); } }, { ALT: function() { $.CONSUME(NodeName); } } ]); }); $.RULE("use", function() { $.CONSUME(USE); $.OR([ { ALT: function() { $.CONSUME(Identifier); } }, { ALT: function() { $.CONSUME(NodeName); } } ]); }); $.RULE("singleFieldValue", function() { $.AT_LEAST_ONE(function() { $.OR([ { ALT: function() { $.SUBRULE($.node); } }, { ALT: function() { $.SUBRULE($.use); } }, { ALT: function() { $.CONSUME(StringLiteral); } }, { ALT: function() { $.CONSUME(HexLiteral); } }, { ALT: function() { $.CONSUME(NumberLiteral); } }, { ALT: function() { $.CONSUME(TrueLiteral); } }, { ALT: function() { $.CONSUME(FalseLiteral); } }, { ALT: function() { $.CONSUME(NullLiteral); } } ]); }); }); $.RULE("multiFieldValue", function() { $.CONSUME(LSquare); $.MANY(function() { $.OR([ { ALT: function() { $.SUBRULE($.node); } }, { ALT: function() { $.SUBRULE($.use); } }, { ALT: function() { $.CONSUME(StringLiteral); } }, { ALT: function() { $.CONSUME(HexLiteral); } }, { ALT: function() { $.CONSUME(NumberLiteral); } }, { ALT: function() { $.CONSUME(NullLiteral); } } ]); }); $.CONSUME(RSquare); }); $.RULE("route", function() { $.CONSUME(ROUTE); $.CONSUME(RouteIdentifier); $.CONSUME(TO); $.CONSUME2(RouteIdentifier); }); this.performSelfAnalysis(); } } class Face { constructor(a, b, c) { this.a = a; this.b = b; this.c = c; this.normal = new THREE.Vector3(); } } const TEXTURE_TYPE = { INTENSITY: 1, INTENSITY_ALPHA: 2, RGB: 3, RGBA: 4 }; exports.VRMLLoader = VRMLLoader; //# sourceMappingURL=VRMLLoader.cjs.map