three-stdlib
Version:
stand-alone library of threejs examples
320 lines (319 loc) • 11.1 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const LoaderUtils = require("../_polyfill/LoaderUtils.cjs");
class PLYLoader extends THREE.Loader {
constructor(manager) {
super(manager);
this.propertyNameMapping = {};
}
load(url, onLoad, onProgress, onError) {
const scope = this;
const loader = new THREE.FileLoader(this.manager);
loader.setPath(this.path);
loader.setResponseType("arraybuffer");
loader.setRequestHeader(this.requestHeader);
loader.setWithCredentials(this.withCredentials);
loader.load(
url,
function(text) {
try {
onLoad(scope.parse(text));
} catch (e) {
if (onError) {
onError(e);
} else {
console.error(e);
}
scope.manager.itemError(url);
}
},
onProgress,
onError
);
}
setPropertyNameMapping(mapping) {
this.propertyNameMapping = mapping;
}
parse(data) {
function parseHeader(data2) {
const patternHeader = /ply([\s\S]*)end_header\r?\n/;
let headerText = "";
let headerLength = 0;
const result = patternHeader.exec(data2);
if (result !== null) {
headerText = result[1];
headerLength = new Blob([result[0]]).size;
}
const header = {
comments: [],
elements: [],
headerLength,
objInfo: ""
};
const lines = headerText.split("\n");
let currentElement;
function make_ply_element_property(propertValues, propertyNameMapping) {
const property = { type: propertValues[0] };
if (property.type === "list") {
property.name = propertValues[3];
property.countType = propertValues[1];
property.itemType = propertValues[2];
} else {
property.name = propertValues[1];
}
if (property.name in propertyNameMapping) {
property.name = propertyNameMapping[property.name];
}
return property;
}
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
line = line.trim();
if (line === "")
continue;
const lineValues = line.split(/\s+/);
const lineType = lineValues.shift();
line = lineValues.join(" ");
switch (lineType) {
case "format":
header.format = lineValues[0];
header.version = lineValues[1];
break;
case "comment":
header.comments.push(line);
break;
case "element":
if (currentElement !== void 0) {
header.elements.push(currentElement);
}
currentElement = {};
currentElement.name = lineValues[0];
currentElement.count = parseInt(lineValues[1]);
currentElement.properties = [];
break;
case "property":
currentElement.properties.push(make_ply_element_property(lineValues, scope.propertyNameMapping));
break;
case "obj_info":
header.objInfo = line;
break;
default:
console.log("unhandled", lineType, lineValues);
}
}
if (currentElement !== void 0) {
header.elements.push(currentElement);
}
return header;
}
function parseASCIINumber(n, type) {
switch (type) {
case "char":
case "uchar":
case "short":
case "ushort":
case "int":
case "uint":
case "int8":
case "uint8":
case "int16":
case "uint16":
case "int32":
case "uint32":
return parseInt(n);
case "float":
case "double":
case "float32":
case "float64":
return parseFloat(n);
}
}
function parseASCIIElement(properties, line) {
const values = line.split(/\s+/);
const element = {};
for (let i = 0; i < properties.length; i++) {
if (properties[i].type === "list") {
const list = [];
const n = parseASCIINumber(values.shift(), properties[i].countType);
for (let j = 0; j < n; j++) {
list.push(parseASCIINumber(values.shift(), properties[i].itemType));
}
element[properties[i].name] = list;
} else {
element[properties[i].name] = parseASCIINumber(values.shift(), properties[i].type);
}
}
return element;
}
function parseASCII(data2, header) {
const buffer = {
indices: [],
vertices: [],
normals: [],
uvs: [],
faceVertexUvs: [],
colors: []
};
let result;
const patternBody = /end_header\s([\s\S]*)$/;
let body = "";
if ((result = patternBody.exec(data2)) !== null) {
body = result[1];
}
const lines = body.split("\n");
let currentElement = 0;
let currentElementCount = 0;
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
line = line.trim();
if (line === "") {
continue;
}
if (currentElementCount >= header.elements[currentElement].count) {
currentElement++;
currentElementCount = 0;
}
const element = parseASCIIElement(header.elements[currentElement].properties, line);
handleElement(buffer, header.elements[currentElement].name, element);
currentElementCount++;
}
return postProcess(buffer);
}
function postProcess(buffer) {
let geometry2 = new THREE.BufferGeometry();
if (buffer.indices.length > 0) {
geometry2.setIndex(buffer.indices);
}
geometry2.setAttribute("position", new THREE.Float32BufferAttribute(buffer.vertices, 3));
if (buffer.normals.length > 0) {
geometry2.setAttribute("normal", new THREE.Float32BufferAttribute(buffer.normals, 3));
}
if (buffer.uvs.length > 0) {
geometry2.setAttribute("uv", new THREE.Float32BufferAttribute(buffer.uvs, 2));
}
if (buffer.colors.length > 0) {
geometry2.setAttribute("color", new THREE.Float32BufferAttribute(buffer.colors, 3));
}
if (buffer.faceVertexUvs.length > 0) {
geometry2 = geometry2.toNonIndexed();
geometry2.setAttribute("uv", new THREE.Float32BufferAttribute(buffer.faceVertexUvs, 2));
}
geometry2.computeBoundingSphere();
return geometry2;
}
function handleElement(buffer, elementName, element) {
if (elementName === "vertex") {
buffer.vertices.push(element.x, element.y, element.z);
if ("nx" in element && "ny" in element && "nz" in element) {
buffer.normals.push(element.nx, element.ny, element.nz);
}
if ("s" in element && "t" in element) {
buffer.uvs.push(element.s, element.t);
}
if ("red" in element && "green" in element && "blue" in element) {
buffer.colors.push(element.red / 255, element.green / 255, element.blue / 255);
}
} else if (elementName === "face") {
const vertex_indices = element.vertex_indices || element.vertex_index;
const texcoord = element.texcoord;
if (vertex_indices.length === 3) {
buffer.indices.push(vertex_indices[0], vertex_indices[1], vertex_indices[2]);
if (texcoord && texcoord.length === 6) {
buffer.faceVertexUvs.push(texcoord[0], texcoord[1]);
buffer.faceVertexUvs.push(texcoord[2], texcoord[3]);
buffer.faceVertexUvs.push(texcoord[4], texcoord[5]);
}
} else if (vertex_indices.length === 4) {
buffer.indices.push(vertex_indices[0], vertex_indices[1], vertex_indices[3]);
buffer.indices.push(vertex_indices[1], vertex_indices[2], vertex_indices[3]);
}
}
}
function binaryRead(dataview, at, type, little_endian) {
switch (type) {
case "int8":
case "char":
return [dataview.getInt8(at), 1];
case "uint8":
case "uchar":
return [dataview.getUint8(at), 1];
case "int16":
case "short":
return [dataview.getInt16(at, little_endian), 2];
case "uint16":
case "ushort":
return [dataview.getUint16(at, little_endian), 2];
case "int32":
case "int":
return [dataview.getInt32(at, little_endian), 4];
case "uint32":
case "uint":
return [dataview.getUint32(at, little_endian), 4];
case "float32":
case "float":
return [dataview.getFloat32(at, little_endian), 4];
case "float64":
case "double":
return [dataview.getFloat64(at, little_endian), 8];
}
}
function binaryReadElement(dataview, at, properties, little_endian) {
const element = {};
let result, read = 0;
for (let i = 0; i < properties.length; i++) {
if (properties[i].type === "list") {
const list = [];
result = binaryRead(dataview, at + read, properties[i].countType, little_endian);
const n = result[0];
read += result[1];
for (let j = 0; j < n; j++) {
result = binaryRead(dataview, at + read, properties[i].itemType, little_endian);
list.push(result[0]);
read += result[1];
}
element[properties[i].name] = list;
} else {
result = binaryRead(dataview, at + read, properties[i].type, little_endian);
element[properties[i].name] = result[0];
read += result[1];
}
}
return [element, read];
}
function parseBinary(data2, header) {
const buffer = {
indices: [],
vertices: [],
normals: [],
uvs: [],
faceVertexUvs: [],
colors: []
};
const little_endian = header.format === "binary_little_endian";
const body = new DataView(data2, header.headerLength);
let result, loc = 0;
for (let currentElement = 0; currentElement < header.elements.length; currentElement++) {
for (let currentElementCount = 0; currentElementCount < header.elements[currentElement].count; currentElementCount++) {
result = binaryReadElement(body, loc, header.elements[currentElement].properties, little_endian);
loc += result[1];
const element = result[0];
handleElement(buffer, header.elements[currentElement].name, element);
}
}
return postProcess(buffer);
}
let geometry;
const scope = this;
if (data instanceof ArrayBuffer) {
const text = LoaderUtils.decodeText(new Uint8Array(data));
const header = parseHeader(text);
geometry = header.format === "ascii" ? parseASCII(text, header) : parseBinary(data, header);
} else {
geometry = parseASCII(data, parseHeader(data));
}
return geometry;
}
}
exports.PLYLoader = PLYLoader;
//# sourceMappingURL=PLYLoader.cjs.map
;