(function (global, factory) { if (typeof define === "function" && define.amd) { define(["exports", "three", "../libs/chevrotain.module.min.js"], factory); } else if (typeof exports !== "undefined") { factory(exports, require("three"), require("../libs/chevrotain.module.min.js")); } else { var mod = { exports: {} }; factory(mod.exports, global.three, global.chevrotainModuleMin); global.VRMLLoader = mod.exports; } })(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _three, _chevrotainModuleMin) { "use strict"; Object.defineProperty(_exports, "__esModule", { value: true }); _exports.VRMLLoader = void 0; _chevrotainModuleMin = _interopRequireDefault(_chevrotainModuleMin); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } Object.defineProperty(subClass, "prototype", { value: Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }), writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } var VRMLLoader = /*#__PURE__*/function (_Loader) { _inherits(VRMLLoader, _Loader); var _super = _createSuper(VRMLLoader); function VRMLLoader(manager) { var _this; _classCallCheck(this, VRMLLoader); _this = _super.call(this, manager); // dependency check if (typeof _chevrotainModuleMin.default === 'undefined') { // eslint-disable-line no-undef throw Error('THREE.VRMLLoader: External library chevrotain.min.js required.'); } return _this; } _createClass(VRMLLoader, [{ key: "load", value: function load(url, onLoad, onProgress, onError) { var scope = this; var path = scope.path === '' ? _three.LoaderUtils.extractUrlBase(url) : scope.path; var 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); } }, { key: "parse", value: function parse(data, path) { var nodeMap = {}; function generateVRMLTree(data) { // create lexer, parser and visitor var tokenData = createTokens(); var lexer = new VRMLLexer(tokenData.tokens); var parser = new VRMLParser(tokenData.tokenVocabulary); var visitor = createVisitor(parser.getBaseCstVisitorConstructor()); // lexing var lexingResult = lexer.lex(data); parser.input = lexingResult.tokens; // parsing var cstOutput = parser.vrml(); if (parser.errors.length > 0) { console.error(parser.errors); throw Error('THREE.VRMLLoader: Parsing errors detected.'); } // actions var ast = visitor.visit(cstOutput); return ast; } function createTokens() { var createToken = _chevrotainModuleMin.default.createToken; // eslint-disable-line no-undef // from http://gun.teipir.gr/VRML-amgem/spec/part1/concepts.html#SyntaxBasics var RouteIdentifier = 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]*/ }); var Identifier = 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 }); // from http://gun.teipir.gr/VRML-amgem/spec/part1/nodesRef.html var 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 ]; // var Version = createToken({ name: 'Version', pattern: /#VRML.*/, longer_alt: Identifier }); var NodeName = createToken({ name: 'NodeName', pattern: new RegExp(nodeTypes.join('|')), longer_alt: Identifier }); var DEF = createToken({ name: 'DEF', pattern: /DEF/, longer_alt: Identifier }); var USE = createToken({ name: 'USE', pattern: /USE/, longer_alt: Identifier }); var ROUTE = createToken({ name: 'ROUTE', pattern: /ROUTE/, longer_alt: Identifier }); var TO = createToken({ name: 'TO', pattern: /TO/, longer_alt: Identifier }); // var StringLiteral = createToken({ name: 'StringLiteral', pattern: /"(:?[^\\"\n\r]+|\\(:?[bfnrtv"\\/]|u[0-9a-fA-F]{4}))*"/ }); var HexLiteral = createToken({ name: 'HexLiteral', pattern: /0[xX][0-9a-fA-F]+/ }); var NumberLiteral = createToken({ name: 'NumberLiteral', pattern: /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/ }); var TrueLiteral = createToken({ name: 'TrueLiteral', pattern: /TRUE/ }); var FalseLiteral = createToken({ name: 'FalseLiteral', pattern: /FALSE/ }); var NullLiteral = createToken({ name: 'NullLiteral', pattern: /NULL/ }); var LSquare = createToken({ name: 'LSquare', pattern: /\[/ }); var RSquare = createToken({ name: 'RSquare', pattern: /]/ }); var LCurly = createToken({ name: 'LCurly', pattern: /{/ }); var RCurly = createToken({ name: 'RCurly', pattern: /}/ }); var Comment = createToken({ name: 'Comment', pattern: /#.*/, group: _chevrotainModuleMin.default.Lexer.SKIPPED // eslint-disable-line no-undef }); // commas, blanks, tabs, newlines and carriage returns are whitespace characters wherever they appear outside of string fields var WhiteSpace = createToken({ name: 'WhiteSpace', pattern: /[ ,\s]/, group: _chevrotainModuleMin.default.Lexer.SKIPPED // eslint-disable-line no-undef }); var 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]; var tokenVocabulary = {}; for (var i = 0, l = tokens.length; i < l; i++) { var token = tokens[i]; tokenVocabulary[token.name] = token; } return { tokens: tokens, tokenVocabulary: tokenVocabulary }; } function createVisitor(BaseVRMLVisitor) { // the visitor is created dynmaically based on the given base class function VRMLToASTVisitor() { BaseVRMLVisitor.call(this); this.validateVisitor(); } VRMLToASTVisitor.prototype = Object.assign(Object.create(BaseVRMLVisitor.prototype), { constructor: VRMLToASTVisitor, vrml: function vrml(ctx) { var data = { version: this.visit(ctx.version), nodes: [], routes: [] }; for (var i = 0, l = ctx.node.length; i < l; i++) { var node = ctx.node[i]; data.nodes.push(this.visit(node)); } if (ctx.route) { for (var _i = 0, _l = ctx.route.length; _i < _l; _i++) { var route = ctx.route[_i]; data.routes.push(this.visit(route)); } } return data; }, version: function version(ctx) { return ctx.Version[0].image; }, node: function node(ctx) { var data = { name: ctx.NodeName[0].image, fields: [] }; if (ctx.field) { for (var i = 0, l = ctx.field.length; i < l; i++) { var field = ctx.field[i]; data.fields.push(this.visit(field)); } } // DEF if (ctx.def) { data.DEF = this.visit(ctx.def[0]); } return data; }, field: function field(ctx) { var data = { name: ctx.Identifier[0].image, type: null, values: null }; var result; // SFValue if (ctx.singleFieldValue) { result = this.visit(ctx.singleFieldValue[0]); } // MFValue if (ctx.multiFieldValue) { result = this.visit(ctx.multiFieldValue[0]); } data.type = result.type; data.values = result.values; return data; }, def: function def(ctx) { return (ctx.Identifier || ctx.NodeName)[0].image; }, use: function use(ctx) { return { USE: (ctx.Identifier || ctx.NodeName)[0].image }; }, singleFieldValue: function singleFieldValue(ctx) { return processField(this, ctx); }, multiFieldValue: function multiFieldValue(ctx) { return processField(this, ctx); }, route: function route(ctx) { var data = { FROM: ctx.RouteIdentifier[0].image, TO: ctx.RouteIdentifier[1].image }; return data; } }); function processField(scope, ctx) { var field = { type: null, values: [] }; if (ctx.node) { field.type = 'node'; for (var i = 0, l = ctx.node.length; i < l; i++) { var node = ctx.node[i]; field.values.push(scope.visit(node)); } } if (ctx.use) { field.type = 'use'; for (var _i2 = 0, _l2 = ctx.use.length; _i2 < _l2; _i2++) { var use = ctx.use[_i2]; field.values.push(scope.visit(use)); } } if (ctx.StringLiteral) { field.type = 'string'; for (var _i3 = 0, _l3 = ctx.StringLiteral.length; _i3 < _l3; _i3++) { var stringLiteral = ctx.StringLiteral[_i3]; field.values.push(stringLiteral.image.replace(/'|"/g, '')); } } if (ctx.NumberLiteral) { field.type = 'number'; for (var _i4 = 0, _l4 = ctx.NumberLiteral.length; _i4 < _l4; _i4++) { var numberLiteral = ctx.NumberLiteral[_i4]; field.values.push(parseFloat(numberLiteral.image)); } } if (ctx.HexLiteral) { field.type = 'hex'; for (var _i5 = 0, _l5 = ctx.HexLiteral.length; _i5 < _l5; _i5++) { var hexLiteral = ctx.HexLiteral[_i5]; field.values.push(hexLiteral.image); } } if (ctx.TrueLiteral) { field.type = 'boolean'; for (var _i6 = 0, _l6 = ctx.TrueLiteral.length; _i6 < _l6; _i6++) { var trueLiteral = ctx.TrueLiteral[_i6]; if (trueLiteral.image === 'TRUE') field.values.push(true); } } if (ctx.FalseLiteral) { field.type = 'boolean'; for (var _i7 = 0, _l7 = ctx.FalseLiteral.length; _i7 < _l7; _i7++) { var falseLiteral = ctx.FalseLiteral[_i7]; 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(tree) { // console.log( JSON.stringify( tree, null, 2 ) ); var nodes = tree.nodes; var scene = new _three.Scene(); // first iteration: build nodemap based on DEF statements for (var i = 0, l = nodes.length; i < l; i++) { var node = nodes[i]; buildNodeMap(node); } // second iteration: build nodes for (var _i8 = 0, _l8 = nodes.length; _i8 < _l8; _i8++) { var _node = nodes[_i8]; var object = getNode(_node); if (object instanceof _three.Object3D) scene.add(object); if (_node.name === 'WorldInfo') scene.userData.worldInfo = object; } return scene; } function buildNodeMap(node) { if (node.DEF) { nodeMap[node.DEF] = node; } var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; if (field.type === 'node') { var fieldValues = field.values; for (var j = 0, jl = fieldValues.length; j < jl; j++) { buildNodeMap(fieldValues[j]); } } } } function getNode(node) { // handle case where a node refers to a different one if (node.USE) { return resolveUSE(node.USE); } if (node.build !== undefined) return node.build; node.build = buildNode(node); return node.build; } // node builder function buildNode(node) { var nodeName = node.name; var 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': // node not supported yet break; default: console.warn('THREE.VRMLLoader: Unknown node:', nodeName); break; } if (build !== undefined && node.DEF !== undefined && build.hasOwnProperty('name') === true) { build.name = node.DEF; } return build; } function buildGroupingNode(node) { var object = new _three.Group(); // var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var fieldValues = field.values; switch (fieldName) { case 'bboxCenter': // field not supported break; case 'bboxSize': // field not supported break; case 'center': // field not supported break; case 'children': parseFieldChildren(fieldValues, object); break; case 'collide': // field not supported break; case 'rotation': var axis = new _three.Vector3(fieldValues[0], fieldValues[1], fieldValues[2]); var angle = fieldValues[3]; object.quaternion.setFromAxisAngle(axis, angle); break; case 'scale': object.scale.set(fieldValues[0], fieldValues[1], fieldValues[2]); break; case 'scaleOrientation': // field not supported break; case 'translation': object.position.set(fieldValues[0], fieldValues[1], fieldValues[2]); break; case 'proxy': // field not supported break; default: console.warn('THREE.VRMLLoader: Unknown field:', fieldName); break; } } return object; } function buildBackgroundNode(node) { var group = new _three.Group(); var groundAngle, groundColor; var skyAngle, skyColor; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var fieldValues = field.values; switch (fieldName) { case 'groundAngle': groundAngle = fieldValues; break; case 'groundColor': groundColor = fieldValues; break; case 'backUrl': // field not supported break; case 'bottomUrl': // field not supported break; case 'frontUrl': // field not supported break; case 'leftUrl': // field not supported break; case 'rightUrl': // field not supported break; case 'topUrl': // field not supported break; case 'skyAngle': skyAngle = fieldValues; break; case 'skyColor': skyColor = fieldValues; break; default: console.warn('THREE.VRMLLoader: Unknown field:', fieldName); break; } } var radius = 10000; // sky if (skyColor) { var skyGeometry = new _three.SphereGeometry(radius, 32, 16); var 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]); } var sky = new _three.Mesh(skyGeometry, skyMaterial); group.add(sky); } // ground if (groundColor) { if (groundColor.length > 0) { var groundGeometry = new _three.SphereGeometry(radius, 32, 16, 0, 2 * Math.PI, 0.5 * Math.PI, 1.5 * Math.PI); var groundMaterial = new _three.MeshBasicMaterial({ fog: false, side: _three.BackSide, vertexColors: true, depthWrite: false, depthTest: false }); paintFaces(groundGeometry, radius, groundAngle, toColorArray(groundColor), false); var ground = new _three.Mesh(groundGeometry, groundMaterial); group.add(ground); } } // render background group first group.renderOrder = -Infinity; return group; } function buildShapeNode(node) { var fields = node.fields; // if the appearance field is NULL or unspecified, lighting is off and the unlit object color is (0, 0, 0) var material = new _three.MeshBasicMaterial({ color: 0x000000 }); var geometry; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var 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; } } // build 3D object var object; if (geometry && geometry.attributes.position) { var type = geometry._type; if (type === 'points') { // points var pointsMaterial = new _three.PointsMaterial({ color: 0xffffff }); if (geometry.attributes.color !== undefined) { pointsMaterial.vertexColors = true; } else { // if the color field is NULL and there is a material defined for the appearance affecting this PointSet, then use the emissiveColor of the material to draw the points if (material.isMeshPhongMaterial) { pointsMaterial.color.copy(material.emissive); } } object = new _three.Points(geometry, pointsMaterial); } else if (type === 'line') { // lines var lineMaterial = new _three.LineBasicMaterial({ color: 0xffffff }); if (geometry.attributes.color !== undefined) { lineMaterial.vertexColors = true; } else { // if the color field is NULL and there is a material defined for the appearance affecting this IndexedLineSet, then use the emissiveColor of the material to draw the lines if (material.isMeshPhongMaterial) { lineMaterial.color.copy(material.emissive); } } object = new _three.LineSegments(geometry, lineMaterial); } else { // consider meshes // check "solid" hint (it's placed in the geometry but affects the material) if (geometry._solid !== undefined) { material.side = geometry._solid ? _three.FrontSide : _three.DoubleSide; } // check for vertex colors if (geometry.attributes.color !== undefined) { material.vertexColors = true; } object = new _three.Mesh(geometry, material); } } else { object = new _three.Object3D(); // if the geometry field is NULL or no vertices are defined the object is not drawn object.visible = false; } return object; } function buildAppearanceNode(node) { var material = new _three.MeshPhongMaterial(); var transformData; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var fieldValues = field.values; switch (fieldName) { case 'material': if (fieldValues[0] !== null) { var 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 { // if the material field is NULL or unspecified, lighting is off and the unlit object color is (0, 0, 0) material = new _three.MeshBasicMaterial({ color: 0x000000 }); } break; case 'texture': var textureNode = fieldValues[0]; if (textureNode !== null) { if (textureNode.name === 'ImageTexture' || textureNode.name === 'PixelTexture') { material.map = getNode(textureNode); } else {// MovieTexture not supported yet } } break; case 'textureTransform': if (fieldValues[0] !== null) { transformData = getNode(fieldValues[0]); } break; default: console.warn('THREE.VRMLLoader: Unknown field:', fieldName); break; } } // only apply texture transform data if a texture was defined if (material.map) { // respect VRML lighting model if (material.map.__type) { switch (material.map.__type) { case TEXTURE_TYPE.INTENSITY_ALPHA: material.opacity = 1; // ignore transparency break; case TEXTURE_TYPE.RGB: material.color.set(0xffffff); // ignore material color break; case TEXTURE_TYPE.RGBA: material.color.set(0xffffff); // ignore material color material.opacity = 1; // ignore transparency break; default: } delete material.map.__type; } // apply texture transform 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) { var materialData = {}; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var fieldValues = field.values; switch (fieldName) { case 'ambientIntensity': // field not supported 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) { var value; switch (textureType) { case TEXTURE_TYPE.INTENSITY: // Intensity texture: A one-component image specifies one-byte hexadecimal or integer values representing the intensity of the image value = parseInt(hex); color.r = value; color.g = value; color.b = value; break; case TEXTURE_TYPE.INTENSITY_ALPHA: // Intensity+Alpha texture: A two-component image specifies the intensity in the first (high) byte and the alpha opacity in the second (low) byte. 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: // RGB texture: Pixels in a three-component image specify the red component in the first (high) byte, followed by the green and blue components color.r = parseInt('0x' + hex.substring(2, 4)); color.g = parseInt('0x' + hex.substring(4, 6)); color.b = parseInt('0x' + hex.substring(6, 8)); break; case TEXTURE_TYPE.RGBA: // RGBA texture: Four-component images specify the alpha opacity byte after red/green/blue 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; default: } } function getTextureType(num_components) { var 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; default: } return type; } function buildPixelTextureNode(node) { var texture; var wrapS = _three.RepeatWrapping; var wrapT = _three.RepeatWrapping; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var fieldValues = field.values; switch (fieldName) { case 'image': var width = fieldValues[0]; var height = fieldValues[1]; var num_components = fieldValues[2]; var useAlpha = num_components === 2 || num_components === 4; var textureType = getTextureType(num_components); var size = (useAlpha === true ? 4 : 3) * (width * height); var _data = new Uint8Array(size); var color = { r: 0, g: 0, b: 0, a: 0 }; for (var j = 3, k = 0, jl = fieldValues.length; j < jl; j++, k++) { parseHexColor(fieldValues[j], textureType, color); if (useAlpha === true) { var stride = k * 4; _data[stride + 0] = color.r; _data[stride + 1] = color.g; _data[stride + 2] = color.b; _data[stride + 3] = color.a; } else { var _stride = k * 3; _data[_stride + 0] = color.r; _data[_stride + 1] = color.g; _data[_stride + 2] = color.b; } } texture = new _three.DataTexture(_data, width, height, useAlpha === true ? _three.RGBAFormat : _three.RGBFormat); texture.__type = textureType; // needed for material modifications 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) { var texture; var wrapS = _three.RepeatWrapping; var wrapT = _three.RepeatWrapping; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var fieldValues = field.values; switch (fieldName) { case 'url': var 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) { var transformData = { center: new _three.Vector2(), rotation: new _three.Vector2(), scale: new _three.Vector2(), translation: new _three.Vector2() }; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var 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) { var worldInfo = {}; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var 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) { var color, coord, normal, texCoord; var ccw = true, solid = true, creaseAngle = 0; var colorIndex, coordIndex, normalIndex, texCoordIndex; var colorPerVertex = true, normalPerVertex = true; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var fieldValues = field.values; switch (fieldName) { case 'color': var colorNode = fieldValues[0]; if (colorNode !== null) { color = getNode(colorNode); } break; case 'coord': var coordNode = fieldValues[0]; if (coordNode !== null) { coord = getNode(coordNode); } break; case 'normal': var normalNode = fieldValues[0]; if (normalNode !== null) { normal = getNode(normalNode); } break; case 'texCoord': var 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': // field not supported 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 === undefined) { console.warn('THREE.VRMLLoader: Missing coordIndex.'); return new _three.BufferGeometry(); // handle VRML files with incomplete geometry definition } var triangulatedCoordIndex = triangulateFaceIndex(coordIndex, ccw); var colorAttribute; var normalAttribute; var uvAttribute; if (color) { if (colorPerVertex === true) { if (colorIndex && colorIndex.length > 0) { // if the colorIndex field is not empty, then it is used to choose colors for each vertex of the IndexedFaceSet. var triangulatedColorIndex = triangulateFaceIndex(colorIndex, ccw); colorAttribute = computeAttributeFromIndexedData(triangulatedCoordIndex, triangulatedColorIndex, color, 3); } else { // if the colorIndex field is empty, then the coordIndex field is used to choose colors from the Color node colorAttribute = toNonIndexedAttribute(triangulatedCoordIndex, new _three.Float32BufferAttribute(color, 3)); } } else { if (colorIndex && colorIndex.length > 0) { // if the colorIndex field is not empty, then they are used to choose one color for each face of the IndexedFaceSet var flattenFaceColors = flattenData(color, colorIndex); var triangulatedFaceColors = triangulateFaceData(flattenFaceColors, coordIndex); colorAttribute = computeAttributeFromFaceData(triangulatedCoordIndex, triangulatedFaceColors); } else { // if the colorIndex field is empty, then the color are applied to each face of the IndexedFaceSet in order var _triangulatedFaceColors = triangulateFaceData(color, coordIndex); colorAttribute = computeAttributeFromFaceData(triangulatedCoordIndex, _triangulatedFaceColors); } } } if (normal) { if (normalPerVertex === true) { // consider vertex normals if (normalIndex && normalIndex.length > 0) { // if the normalIndex field is not empty, then it is used to choose normals for each vertex of the IndexedFaceSet. var triangulatedNormalIndex = triangulateFaceIndex(normalIndex, ccw); normalAttribute = computeAttributeFromIndexedData(triangulatedCoordIndex, triangulatedNormalIndex, normal, 3); } else { // if the normalIndex field is empty, then the coordIndex field is used to choose normals from the Normal node normalAttribute = toNonIndexedAttribute(triangulatedCoordIndex, new _three.Float32BufferAttribute(normal, 3)); } } else { // consider face normals if (normalIndex && normalIndex.length > 0) { // if the normalIndex field is not empty, then they are used to choose one normal for each face of the IndexedFaceSet var flattenFaceNormals = flattenData(normal, normalIndex); var triangulatedFaceNormals = triangulateFaceData(flattenFaceNormals, coordIndex); normalAttribute = computeAttributeFromFaceData(triangulatedCoordIndex, triangulatedFaceNormals); } else { // if the normalIndex field is empty, then the normals are applied to each face of the IndexedFaceSet in order var _triangulatedFaceNormals = triangulateFaceData(normal, coordIndex); normalAttribute = computeAttributeFromFaceData(triangulatedCoordIndex, _triangulatedFaceNormals); } } } else { // if the normal field is NULL, then the loader should automatically generate normals, using creaseAngle to determine if and how normals are smoothed across shared vertices normalAttribute = computeNormalAttribute(triangulatedCoordIndex, coord, creaseAngle); } if (texCoord) { // texture coordinates are always defined on vertex level if (texCoordIndex && texCoordIndex.length > 0) { // if the texCoordIndex field is not empty, then it is used to choose texture coordinates for each vertex of the IndexedFaceSet. var triangulatedTexCoordIndex = triangulateFaceIndex(texCoordIndex, ccw); uvAttribute = computeAttributeFromIndexedData(triangulatedCoordIndex, triangulatedTexCoordIndex, texCoord, 2); } else { // if the texCoordIndex field is empty, then the coordIndex array is used to choose texture coordinates from the TextureCoordinate node uvAttribute = toNonIndexedAttribute(triangulatedCoordIndex, new _three.Float32BufferAttribute(texCoord, 2)); } } var geometry = new _three.BufferGeometry(); var positionAttribute = toNonIndexedAttribute(triangulatedCoordIndex, new _three.Float32BufferAttribute(coord, 3)); geometry.setAttribute('position', positionAttribute); geometry.setAttribute('normal', normalAttribute); // optional attributes if (colorAttribute) geometry.setAttribute('color', colorAttribute); if (uvAttribute) geometry.setAttribute('uv', uvAttribute); // "solid" influences the material so let's store it for later use geometry._solid = solid; geometry._type = 'mesh'; return geometry; } function buildIndexedLineSetNode(node) { var color, coord; var colorIndex, coordIndex; var colorPerVertex = true; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var fieldValues = field.values; switch (fieldName) { case 'color': var colorNode = fieldValues[0]; if (colorNode !== null) { color = getNode(colorNode); } break; case 'coord': var 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; } } // build lines var colorAttribute; var expandedLineIndex = expandLineIndex(coordIndex); // create an index for three.js's linesegment primitive if (color) { if (colorPerVertex === true) { if (colorIndex.length > 0) { // if the colorIndex field is not empty, then one color is used for each polyline of the IndexedLineSet. var expandedColorIndex = expandLineIndex(colorIndex); // compute colors for each line segment (rendering primitve) colorAttribute = computeAttributeFromIndexedData(expandedLineIndex, expandedColorIndex, color, 3); // compute data on vertex level } else { // if the colorIndex field is empty, then the colors are applied to each polyline of the IndexedLineSet in order. colorAttribute = toNonIndexedAttribute(expandedLineIndex, new _three.Float32BufferAttribute(color, 3)); } } else { if (colorIndex.length > 0) { // if the colorIndex field is not empty, then colors are applied to each vertex of the IndexedLineSet var flattenLineColors = flattenData(color, colorIndex); // compute colors for each VRML primitve var expandedLineColors = expandLineData(flattenLineColors, coordIndex); // compute colors for each line segment (rendering primitve) colorAttribute = computeAttributeFromLineData(expandedLineIndex, expandedLineColors); // compute data on vertex level } else { // if the colorIndex field is empty, then the coordIndex field is used to choose colors from the Color node var _expandedLineColors = expandLineData(color, coordIndex); // compute colors for each line segment (rendering primitve) colorAttribute = computeAttributeFromLineData(expandedLineIndex, _expandedLineColors); // compute data on vertex level } } } // var geometry = new _three.BufferGeometry(); var 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) { var color, coord; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var fieldValues = field.values; switch (fieldName) { case 'color': var colorNode = fieldValues[0]; if (colorNode !== null) { color = getNode(colorNode); } break; case 'coord': var coordNode = fieldValues[0]; if (coordNode !== null) { coord = getNode(coordNode); } break; default: console.warn('THREE.VRMLLoader: Unknown field:', fieldName); break; } } var 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) { var size = new _three.Vector3(2, 2, 2); var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var 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; } } var geometry = new _three.BoxGeometry(size.x, size.y, size.z); return geometry; } function buildConeNode(node) { var radius = 1, height = 2, openEnded = false; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var 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': // field not supported break; default: console.warn('THREE.VRMLLoader: Unknown field:', fieldName); break; } } var geometry = new _three.ConeGeometry(radius, height, 16, 1, openEnded); return geometry; } function buildCylinderNode(node) { var radius = 1, height = 2; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var fieldValues = field.values; switch (fieldName) { case 'bottom': // field not supported break; case 'radius': radius = fieldValues[0]; break; case 'height': height = fieldValues[0]; break; case 'side': // field not supported break; case 'top': // field not supported break; default: console.warn('THREE.VRMLLoader: Unknown field:', fieldName); break; } } var geometry = new _three.CylinderGeometry(radius, radius, height, 16, 1); return geometry; } function buildSphereNode(node) { var radius = 1; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var fieldValues = field.values; switch (fieldName) { case 'radius': radius = fieldValues[0]; break; default: console.warn('THREE.VRMLLoader: Unknown field:', fieldName); break; } } var geometry = new _three.SphereGeometry(radius, 16, 16); return geometry; } function buildElevationGridNode(node) { var color; var normal; var texCoord; var height; var colorPerVertex = true; var normalPerVertex = true; var solid = true; var ccw = true; var creaseAngle = 0; var xDimension = 2; var zDimension = 2; var xSpacing = 1; var zSpacing = 1; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var fieldValues = field.values; switch (fieldName) { case 'color': var colorNode = fieldValues[0]; if (colorNode !== null) { color = getNode(colorNode); } break; case 'normal': var normalNode = fieldValues[0]; if (normalNode !== null) { normal = getNode(normalNode); } break; case 'texCoord': var 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; } } // vertex data var vertices = []; var normals = []; var colors = []; var uvs = []; for (var _i9 = 0; _i9 < zDimension; _i9++) { for (var j = 0; j < xDimension; j++) { // compute a row major index var index = _i9 * xDimension + j; // vertices var x = xSpacing * _i9; var y = height[index]; var z = zSpacing * j; vertices.push(x, y, z); // colors if (color && colorPerVertex === true) { var r = color[index * 3 + 0]; var g = color[index * 3 + 1]; var b = color[index * 3 + 2]; colors.push(r, g, b); } // normals if (normal && normalPerVertex === true) { var xn = normal[index * 3 + 0]; var yn = normal[index * 3 + 1]; var zn = normal[index * 3 + 2]; normals.push(xn, yn, zn); } // uvs if (texCoord) { var s = texCoord[index * 2 + 0]; var t = texCoord[index * 2 + 1]; uvs.push(s, t); } else { uvs.push(_i9 / (xDimension - 1), j / (zDimension - 1)); } } } // indices var indices = []; for (var _i10 = 0; _i10 < xDimension - 1; _i10++) { for (var _j = 0; _j < zDimension - 1; _j++) { // from https://tecfa.unige.ch/guides/vrml/vrml97/spec/part1/nodesRef.html#ElevationGrid var a = _i10 + _j * xDimension; var _b = _i10 + (_j + 1) * xDimension; var c = _i10 + 1 + (_j + 1) * xDimension; var d = _i10 + 1 + _j * xDimension; // faces if (ccw === true) { indices.push(a, c, _b); indices.push(c, a, d); } else { indices.push(a, _b, c); indices.push(c, d, a); } } } // var positionAttribute = toNonIndexedAttribute(indices, new _three.Float32BufferAttribute(vertices, 3)); var uvAttribute = toNonIndexedAttribute(indices, new _three.Float32BufferAttribute(uvs, 2)); var colorAttribute; var normalAttribute; // color attribute if (color) { if (colorPerVertex === false) { for (var _i11 = 0; _i11 < xDimension - 1; _i11++) { for (var _j2 = 0; _j2 < zDimension - 1; _j2++) { var _index = _i11 + _j2 * (xDimension - 1); var _r = color[_index * 3 + 0]; var _g = color[_index * 3 + 1]; var _b2 = color[_index * 3 + 2]; // one color per quad colors.push(_r, _g, _b2); colors.push(_r, _g, _b2); colors.push(_r, _g, _b2); colors.push(_r, _g, _b2); colors.push(_r, _g, _b2); colors.push(_r, _g, _b2); } } colorAttribute = new _three.Float32BufferAttribute(colors, 3); } else { colorAttribute = toNonIndexedAttribute(indices, new _three.Float32BufferAttribute(colors, 3)); } } // normal attribute if (normal) { if (normalPerVertex === false) { for (var _i12 = 0; _i12 < xDimension - 1; _i12++) { for (var _j3 = 0; _j3 < zDimension - 1; _j3++) { var _index2 = _i12 + _j3 * (xDimension - 1); var _xn = normal[_index2 * 3 + 0]; var _yn = normal[_index2 * 3 + 1]; var _zn = normal[_index2 * 3 + 2]; // one normal per quad 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); } // build geometry var geometry = new _three.BufferGeometry(); geometry.setAttribute('position', positionAttribute); geometry.setAttribute('normal', normalAttribute); geometry.setAttribute('uv', uvAttribute); if (colorAttribute) geometry.setAttribute('color', colorAttribute); // "solid" influences the material so let's store it for later use geometry._solid = solid; geometry._type = 'mesh'; return geometry; } function buildExtrusionNode(node) { var crossSection = [1, 1, 1, -1, -1, -1, -1, 1, 1, 1]; var spine = [0, 0, 0, 0, 1, 0]; var scale; var orientation; var beginCap = true; var ccw = true; var creaseAngle = 0; var endCap = true; var solid = true; var fields = node.fields; for (var i = 0, l = fields.length; i < l; i++) { var field = fields[i]; var fieldName = field.name; var fieldValues = field.values; switch (fieldName) { case 'beginCap': beginCap = fieldValues[0]; break; case 'ccw': ccw = fieldValues[0]; break; case 'convex': // field not supported 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; // only extrusion along the Y-axis are supported so far break; default: console.warn('THREE.VRMLLoader: Unknown field:', fieldName); break; } } var crossSectionClosed = crossSection[0] === crossSection[crossSection.length - 2] && crossSection[1] === crossSection[crossSection.length - 1]; // vertices var vertices = []; var spineVector = new _three.Vector3(); var scaling = new _three.Vector3(); var axis = new _three.Vector3(); var vertex = new _three.Vector3(); var quaternion = new _three.Quaternion(); for (var _i13 = 0, j = 0, o = 0, il = spine.length; _i13 < il; _i13 += 3, j += 2, o += 4) { spineVector.fromArray(spine, _i13); 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; var angle = orientation ? orientation[o + 3] : 0; for (var k = 0, kl = crossSection.length; k < kl; k += 2) { vertex.x = crossSection[k + 0]; vertex.y = 0; vertex.z = crossSection[k + 1]; // scale vertex.multiply(scaling); // rotate quaternion.setFromAxisAngle(axis, angle); vertex.applyQuaternion(quaternion); // translate vertex.add(spineVector); vertices.push(vertex.x, vertex.y, vertex.z); } } // indices var indices = []; var spineCount = spine.length / 3; var crossSectionCount = crossSection.length / 2; for (var _i14 = 0; _i14 < spineCount - 1; _i14++) { for (var _j4 = 0; _j4 < crossSectionCount - 1; _j4++) { var a = _j4 + _i14 * crossSectionCount; var b = _j4 + 1 + _i14 * crossSectionCount; var c = _j4 + (_i14 + 1) * crossSectionCount; var d = _j4 + 1 + (_i14 + 1) * crossSectionCount; if (_j4 === crossSectionCount - 2 && crossSectionClosed === true) { b = _i14 * crossSectionCount; d = (_i14 + 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); } } } // triangulate cap if (beginCap === true || endCap === true) { var contour = []; for (var _i15 = 0, _l9 = crossSection.length; _i15 < _l9; _i15 += 2) { contour.push(new _three.Vector2(crossSection[_i15], crossSection[_i15 + 1])); } var faces = _three.ShapeUtils.triangulateShape(contour, []); var capIndices = []; for (var _i16 = 0, _l10 = faces.length; _i16 < _l10; _i16++) { var face = faces[_i16]; capIndices.push(face[0], face[1], face[2]); } // begin cap if (beginCap === true) { for (var _i17 = 0, _l11 = capIndices.length; _i17 < _l11; _i17 += 3) { if (ccw === true) { indices.push(capIndices[_i17 + 0], capIndices[_i17 + 1], capIndices[_i17 + 2]); } else { indices.push(capIndices[_i17 + 0], capIndices[_i17 + 2], capIndices[_i17 + 1]); } } } // end cap if (endCap === true) { var indexOffset = crossSectionCount * (spineCount - 1); // references to the first vertex of the last cross section for (var _i18 = 0, _l12 = capIndices.length; _i18 < _l12; _i18 += 3) { if (ccw === true) { indices.push(indexOffset + capIndices[_i18 + 0], indexOffset + capIndices[_i18 + 2], indexOffset + capIndices[_i18 + 1]); } else { indices.push(indexOffset + capIndices[_i18 + 0], indexOffset + capIndices[_i18 + 1], indexOffset + capIndices[_i18 + 2]); } } } } var positionAttribute = toNonIndexedAttribute(indices, new _three.Float32BufferAttribute(vertices, 3)); var normalAttribute = computeNormalAttribute(indices, vertices, creaseAngle); var geometry = new _three.BufferGeometry(); geometry.setAttribute('position', positionAttribute); geometry.setAttribute('normal', normalAttribute); // no uvs yet // "solid" influences the material so let's store it for later use geometry._solid = solid; geometry._type = 'mesh'; return geometry; } // helper functions function resolveUSE(identifier) { var node = nodeMap[identifier]; var build = getNode(node); // because the same 3D objects can have different transformations, it's necessary to clone them. // materials can be influenced by the geometry (e.g. vertex normals). cloning is necessary to avoid // any side effects return build.isObject3D || build.isMaterial ? build.clone() : build; } function parseFieldChildren(children, owner) { for (var i = 0, l = children.length; i < l; i++) { var object = getNode(children[i]); if (object instanceof _three.Object3D) owner.add(object); } } function triangulateFaceIndex(index, ccw) { var indices = []; // since face defintions can have more than three vertices, it's necessary to // perform a simple triangulation var start = 0; for (var i = 0, l = index.length; i < l; i++) { var i1 = index[start]; var i2 = index[i + (ccw ? 1 : 2)]; var i3 = index[i + (ccw ? 2 : 1)]; indices.push(i1, i2, i3); // an index of -1 indicates that the current face has ended and the next one begins if (index[i + 3] === -1 || i + 3 >= l) { i += 3; start = i + 1; } } return indices; } function triangulateFaceData(data, index) { var triangulatedData = []; var start = 0; for (var i = 0, l = index.length; i < l; i++) { var stride = start * 3; var x = data[stride]; var y = data[stride + 1]; var z = data[stride + 2]; triangulatedData.push(x, y, z); // an index of -1 indicates that the current face has ended and the next one begins if (index[i + 3] === -1 || i + 3 >= l) { i += 3; start++; } } return triangulatedData; } function flattenData(data, index) { var flattenData = []; for (var i = 0, l = index.length; i < l; i++) { var i1 = index[i]; var stride = i1 * 3; var x = data[stride]; var y = data[stride + 1]; var z = data[stride + 2]; flattenData.push(x, y, z); } return flattenData; } function expandLineIndex(index) { var indices = []; for (var i = 0, l = index.length; i < l; i++) { var i1 = index[i]; var i2 = index[i + 1]; indices.push(i1, i2); // an index of -1 indicates that the current line has ended and the next one begins if (index[i + 2] === -1 || i + 2 >= l) { i += 2; } } return indices; } function expandLineData(data, index) { var triangulatedData = []; var start = 0; for (var i = 0, l = index.length; i < l; i++) { var stride = start * 3; var x = data[stride]; var y = data[stride + 1]; var z = data[stride + 2]; triangulatedData.push(x, y, z); // an index of -1 indicates that the current line has ended and the next one begins if (index[i + 2] === -1 || i + 2 >= l) { i += 2; start++; } } return triangulatedData; } var vA = new _three.Vector3(); var vB = new _three.Vector3(); var vC = new _three.Vector3(); var uvA = new _three.Vector2(); var uvB = new _three.Vector2(); var uvC = new _three.Vector2(); function computeAttributeFromIndexedData(coordIndex, index, data, itemSize) { var array = []; // we use the coordIndex.length as delimiter since normalIndex must contain at least as many indices for (var i = 0, l = coordIndex.length; i < l; i += 3) { var a = index[i]; var b = index[i + 1]; var c = index[i + 2]; if (itemSize === 2) { uvA.fromArray(data, a * itemSize); uvB.fromArray(data, b * itemSize); uvC.fromArray(data, c * itemSize); array.push(uvA.x, uvA.y); array.push(uvB.x, uvB.y); array.push(uvC.x, uvC.y); } else { vA.fromArray(data, a * itemSize); vB.fromArray(data, b * itemSize); vC.fromArray(data, 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) { var array = []; for (var 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) { var array = []; for (var 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) { var array = attribute.array; var itemSize = attribute.itemSize; var array2 = new array.constructor(indices.length * itemSize); var index = 0, index2 = 0; for (var i = 0, l = indices.length; i < l; i++) { index = indices[i] * itemSize; for (var j = 0; j < itemSize; j++) { array2[index2++] = array[index++]; } } return new _three.Float32BufferAttribute(array2, itemSize); } var ab = new _three.Vector3(); var cb = new _three.Vector3(); function computeNormalAttribute(index, coord, creaseAngle) { var faces = []; var vertexNormals = {}; // prepare face and raw vertex normals for (var i = 0, l = index.length; i < l; i += 3) { var a = index[i]; var b = index[i + 1]; var c = index[i + 2]; var 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] === undefined) vertexNormals[a] = []; if (vertexNormals[b] === undefined) vertexNormals[b] = []; if (vertexNormals[c] === undefined) vertexNormals[c] = []; vertexNormals[a].push(face.normal); vertexNormals[b].push(face.normal); vertexNormals[c].push(face.normal); faces.push(face); } // compute vertex normals and build final geometry var normals = []; for (var _i19 = 0, _l13 = faces.length; _i19 < _l13; _i19++) { var _face = faces[_i19]; var nA = weightedNormal(vertexNormals[_face.a], _face.normal, creaseAngle); var nB = weightedNormal(vertexNormals[_face.b], _face.normal, creaseAngle); var 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) { var normal = new _three.Vector3(); if (creaseAngle === 0) { normal.copy(vector); } else { for (var i = 0, l = normals.length; i < l; i++) { if (normals[i].angleTo(vector) < creaseAngle) { normal.add(normals[i]); } } } return normal.normalize(); } function toColorArray(colors) { var array = []; for (var i = 0, l = colors.length; i < l; i += 3) { array.push(new _three.Color(colors[i], colors[i + 1], colors[i + 2])); } return array; } /** * Vertically paints the faces interpolating between the * specified colors at the specified angels. This is used for the Background * node, but could be applied to other nodes with multiple faces as well. * * When used with the Background node, default is directionIsDown is true if * interpolating the skyColor down from the Zenith. When interpolationg up from * the Nadir i.e. interpolating the groundColor, the directionIsDown is false. * * The first angle is never specified, it is the Zenith (0 rad). Angles are specified * in radians. The geometry is thought a sphere, but could be anything. The color interpolation * is linear along the Y axis in any case. * * You must specify one more color than you have angles at the beginning of the colors array. * This is the color of the Zenith (the top of the shape). * * @param {BufferGeometry} geometry * @param {number} radius * @param {array} angles * @param {array} colors * @param {boolean} topDown - Whether to work top down or bottom up. */ function paintFaces(geometry, radius, angles, colors, topDown) { // compute threshold values var thresholds = []; var startAngle = topDown === true ? 0 : Math.PI; for (var i = 0, l = colors.length; i < l; i++) { var angle = i === 0 ? 0 : angles[i - 1]; angle = topDown === true ? angle : startAngle - angle; var point = new _three.Vector3(); point.setFromSphericalCoords(radius, angle, 0); thresholds.push(point); } // generate vertex colors var indices = geometry.index; var positionAttribute = geometry.attributes.position; var colorAttribute = new _three.BufferAttribute(new Float32Array(geometry.attributes.position.count * 3), 3); var position = new _three.Vector3(); var color = new _three.Color(); for (var _i20 = 0; _i20 < indices.count; _i20++) { var index = indices.getX(_i20); position.fromBufferAttribute(positionAttribute, index); var thresholdIndexA = void 0, thresholdIndexB = void 0; var t = 1; for (var j = 1; j < thresholds.length; j++) { thresholdIndexA = j - 1; thresholdIndexB = j; var thresholdA = thresholds[thresholdIndexA]; var thresholdB = thresholds[thresholdIndexB]; if (topDown === true) { // interpolation for sky color if (position.y <= thresholdA.y && position.y > thresholdB.y) { t = Math.abs(thresholdA.y - position.y) / Math.abs(thresholdA.y - thresholdB.y); break; } } else { // interpolation for ground color if (position.y >= thresholdA.y && position.y < thresholdB.y) { t = Math.abs(thresholdA.y - position.y) / Math.abs(thresholdA.y - thresholdB.y); break; } } } var colorA = colors[thresholdIndexA]; var colorB = colors[thresholdIndexB]; color.copy(colorA).lerp(colorB, t); colorAttribute.setXYZ(index, color.r, color.g, color.b); } geometry.setAttribute('color', colorAttribute); } // var textureLoader = new _three.TextureLoader(this.manager); textureLoader.setPath(this.resourcePath || path).setCrossOrigin(this.crossOrigin); // check version (only 2.0 is supported) if (data.indexOf('#VRML V2.0') === -1) { throw Error('THREE.VRMLLexer: Version of VRML asset not supported.'); } // create JSON representing the tree structure of the VRML asset var tree = generateVRMLTree(data); // parse the tree structure to a three.js scene var scene = parseTree(tree); return scene; } }]); return VRMLLoader; }(_three.Loader); _exports.VRMLLoader = VRMLLoader; var VRMLLexer = /*#__PURE__*/function () { function VRMLLexer(tokens) { _classCallCheck(this, VRMLLexer); this.lexer = new _chevrotainModuleMin.default.Lexer(tokens); // eslint-disable-line no-undef } _createClass(VRMLLexer, [{ key: "lex", value: function lex(inputText) { var lexingResult = this.lexer.tokenize(inputText); if (lexingResult.errors.length > 0) { console.error(lexingResult.errors); throw Error('THREE.VRMLLexer: Lexing errors detected.'); } return lexingResult; } }]); return VRMLLexer; }(); var CstParser = _chevrotainModuleMin.default.CstParser; // eslint-disable-line no-undef var VRMLParser = /*#__PURE__*/function (_CstParser) { _inherits(VRMLParser, _CstParser); var _super2 = _createSuper(VRMLParser); function VRMLParser(tokenVocabulary) { var _this2; _classCallCheck(this, VRMLParser); _this2 = _super2.call(this, tokenVocabulary); var $ = _assertThisInitialized(_this2); var Version = tokenVocabulary['Version']; var LCurly = tokenVocabulary['LCurly']; var RCurly = tokenVocabulary['RCurly']; var LSquare = tokenVocabulary['LSquare']; var RSquare = tokenVocabulary['RSquare']; var Identifier = tokenVocabulary['Identifier']; var RouteIdentifier = tokenVocabulary['RouteIdentifier']; var StringLiteral = tokenVocabulary['StringLiteral']; var HexLiteral = tokenVocabulary['HexLiteral']; var NumberLiteral = tokenVocabulary['NumberLiteral']; var TrueLiteral = tokenVocabulary['TrueLiteral']; var FalseLiteral = tokenVocabulary['FalseLiteral']; var NullLiteral = tokenVocabulary['NullLiteral']; var DEF = tokenVocabulary['DEF']; var USE = tokenVocabulary['USE']; var ROUTE = tokenVocabulary['ROUTE']; var TO = tokenVocabulary['TO']; var 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 ALT() { $.SUBRULE($.singleFieldValue); } }, { ALT: function ALT() { $.SUBRULE($.multiFieldValue); } }]); }); $.RULE('def', function () { $.CONSUME(DEF); $.OR([{ ALT: function ALT() { $.CONSUME(Identifier); } }, { ALT: function ALT() { $.CONSUME(NodeName); } }]); }); $.RULE('use', function () { $.CONSUME(USE); $.OR([{ ALT: function ALT() { $.CONSUME(Identifier); } }, { ALT: function ALT() { $.CONSUME(NodeName); } }]); }); $.RULE('singleFieldValue', function () { $.AT_LEAST_ONE(function () { $.OR([{ ALT: function ALT() { $.SUBRULE($.node); } }, { ALT: function ALT() { $.SUBRULE($.use); } }, { ALT: function ALT() { $.CONSUME(StringLiteral); } }, { ALT: function ALT() { $.CONSUME(HexLiteral); } }, { ALT: function ALT() { $.CONSUME(NumberLiteral); } }, { ALT: function ALT() { $.CONSUME(TrueLiteral); } }, { ALT: function ALT() { $.CONSUME(FalseLiteral); } }, { ALT: function ALT() { $.CONSUME(NullLiteral); } }]); }); }); $.RULE('multiFieldValue', function () { $.CONSUME(LSquare); $.MANY(function () { $.OR([{ ALT: function ALT() { $.SUBRULE($.node); } }, { ALT: function ALT() { $.SUBRULE($.use); } }, { ALT: function ALT() { $.CONSUME(StringLiteral); } }, { ALT: function ALT() { $.CONSUME(HexLiteral); } }, { ALT: function ALT() { $.CONSUME(NumberLiteral); } }, { ALT: function ALT() { $.CONSUME(NullLiteral); } }]); }); $.CONSUME(RSquare); }); $.RULE('route', function () { $.CONSUME(ROUTE); $.CONSUME(RouteIdentifier); $.CONSUME(TO); $.CONSUME2(RouteIdentifier); }); _this2.performSelfAnalysis(); return _this2; } return _createClass(VRMLParser); }(CstParser); var Face = /*#__PURE__*/_createClass(function Face(a, b, c) { _classCallCheck(this, Face); this.a = a; this.b = b; this.c = c; this.normal = new _three.Vector3(); }); var TEXTURE_TYPE = { INTENSITY: 1, INTENSITY_ALPHA: 2, RGB: 3, RGBA: 4 }; });