three-stdlib
Version:
stand-alone library of threejs examples
1,477 lines • 69.9 kB
JavaScript
import { Loader, LoaderUtils, FileLoader, Vector3, Vector2, TextureLoader, Scene, Object3D, Group, SphereGeometry, MeshBasicMaterial, BackSide, Mesh, PointsMaterial, Points, LineBasicMaterial, LineSegments, FrontSide, DoubleSide, MeshPhongMaterial, Color, DataTexture, BufferGeometry, Float32BufferAttribute, BoxGeometry, ConeGeometry, CylinderGeometry, Quaternion, ShapeUtils, BufferAttribute, RepeatWrapping, ClampToEdgeWrapping } from "three";
import { createToken, Lexer, CstParser } from "../libs/chevrotain.js";
class VRMLLoader extends Loader {
constructor(manager) {
super(manager);
}
load(url, onLoad, onProgress, onError) {
const scope = this;
const path = scope.path === "" ? LoaderUtils.extractUrlBase(url) : scope.path;
const loader = new 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 = 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 = 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 = createToken({
name: "Version",
pattern: /#VRML.*/,
longer_alt: Identifier
});
const NodeName = createToken({
name: "NodeName",
pattern: new RegExp(nodeTypes.join("|")),
longer_alt: Identifier
});
const DEF = createToken({
name: "DEF",
pattern: /DEF/,
longer_alt: Identifier
});
const USE = createToken({
name: "USE",
pattern: /USE/,
longer_alt: Identifier
});
const ROUTE = createToken({
name: "ROUTE",
pattern: /ROUTE/,
longer_alt: Identifier
});
const TO = createToken({
name: "TO",
pattern: /TO/,
longer_alt: Identifier
});
const StringLiteral = 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 = createToken({ name: "HexLiteral", pattern: /0[xX][0-9a-fA-F]+/ });
const NumberLiteral = createToken({ name: "NumberLiteral", pattern: /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/ });
const TrueLiteral = createToken({ name: "TrueLiteral", pattern: /TRUE/ });
const FalseLiteral = createToken({ name: "FalseLiteral", pattern: /FALSE/ });
const NullLiteral = createToken({ name: "NullLiteral", pattern: /NULL/ });
const LSquare = createToken({ name: "LSquare", pattern: /\[/ });
const RSquare = createToken({ name: "RSquare", pattern: /]/ });
const LCurly = createToken({ name: "LCurly", pattern: /{/ });
const RCurly = createToken({ name: "RCurly", pattern: /}/ });
const Comment = createToken({
name: "Comment",
pattern: /#.*/,
group: Lexer.SKIPPED
});
const WhiteSpace = createToken({
name: "WhiteSpace",
pattern: /[ ,\s]/,
group: 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 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 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 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 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 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 SphereGeometry(radius, 32, 16);
const skyMaterial = new MeshBasicMaterial({ fog: false, side: 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 Mesh(skyGeometry, skyMaterial);
group.add(sky);
}
if (groundColor) {
if (groundColor.length > 0) {
const groundGeometry = new SphereGeometry(radius, 32, 16, 0, 2 * Math.PI, 0.5 * Math.PI, 1.5 * Math.PI);
const groundMaterial = new MeshBasicMaterial({
fog: false,
side: BackSide,
vertexColors: true,
depthWrite: false,
depthTest: false
});
paintFaces(groundGeometry, radius, groundAngle, toColorArray(groundColor), false);
const ground = new Mesh(groundGeometry, groundMaterial);
group.add(ground);
}
}
group.renderOrder = -Infinity;
return group;
}
function buildShapeNode(node) {
const fields = node.fields;
let material = new 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 PointsMaterial({ color: 16777215 });
if (geometry.attributes.color !== void 0) {
pointsMaterial.vertexColors = true;
} else {
if (material.isMeshPhongMaterial) {
pointsMaterial.color.copy(material.emissive);
}
}
object = new Points(geometry, pointsMaterial);
} else if (type === "line") {
const lineMaterial = new LineBasicMaterial({ color: 16777215 });
if (geometry.attributes.color !== void 0) {
lineMaterial.vertexColors = true;
} else {
if (material.isMeshPhongMaterial) {
lineMaterial.color.copy(material.emissive);
}
}
object = new LineSegments(geometry, lineMaterial);
} else {
if (geometry._solid !== void 0) {
material.side = geometry._solid ? FrontSide : DoubleSide;
}
if (geometry.attributes.color !== void 0) {
material.vertexColors = true;
}
object = new Mesh(geometry, material);
}
} else {
object = new Object3D();
object.visible = false;
}
return object;
}
function buildAppearanceNode(node) {
let material = new 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 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 Color(fieldValues[0], fieldValues[1], fieldValues[2]);
break;
case "emissiveColor":
materialData.emissiveColor = new Color(fieldValues[0], fieldValues[1], fieldValues[2]);
break;
case "shininess":
materialData.shininess = fieldValues[0];
break;
case "specularColor":
materialData.emissiveColor = new 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 = RepeatWrapping;
let wrapT = 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 DataTexture(data2, width, height);
texture.needsUpdate = true;
texture.__type = textureType;
break;
case "repeatS":
if (fieldValues[0] === false)
wrapS = ClampToEdgeWrapping;
break;
case "repeatT":
if (fieldValues[0] === false)
wrapT = 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 = RepeatWrapping;
let wrapT = 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 = ClampToEdgeWrapping;
break;
case "repeatT":
if (fieldValues[0] === false)
wrapT = 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 Vector2(),
rotation: new Vector2(),
scale: new Vector2(),
translation: new 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 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 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 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 Float32BufferAttribute(texCoord, 2));
}
}
const geometry = new BufferGeometry();
const positionAttribute = toNonIndexedAttribute(triangulatedCoordIndex, new 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 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 BufferGeometry();
const positionAttribute = toNonIndexedAttribute(expandedLineIndex, new 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 BufferGeometry();
geometry.setAttribute("position", new Float32BufferAttribute(coord, 3));
if (color)
geometry.setAttribute("color", new Float32BufferAttribute(color, 3));
geometry._type = "points";
return geometry;
}
function buildBoxNode(node) {
const size = new 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 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 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 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 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 Float32BufferAttribute(vertices, 3));
const uvAttribute = toNonIndexedAttribute(indices, new 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 Float32BufferAttribute(colors, 3);
} else {
colorAttribute = toNonIndexedAttribute(indices, new 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 Float32BufferAttribute(normals, 3);
} else {
normalAttribute = toNonIndexedAttribute(indices, new Float32BufferAttribute(normals, 3));
}
} else {
normalAttribute = computeNormalAttribute(indices, vertices, creaseAngle);
}
const geometry = new 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 geometr